Merge "Fix a remaining View leak in InputMethodManager." into nyc-dev
diff --git a/Android.mk b/Android.mk
index c12a8e7..fc9c319 100644
--- a/Android.mk
+++ b/Android.mk
@@ -197,7 +197,6 @@
core/java/android/net/ICaptivePortal.aidl \
core/java/android/net/IConnectivityManager.aidl \
core/java/android/net/IConnectivityMetricsLogger.aidl \
- core/java/android/net/IConnectivityMetricsLoggerSubscriber.aidl \
core/java/android/net/IEthernetManager.aidl \
core/java/android/net/IEthernetServiceListener.aidl \
core/java/android/net/INetworkManagementEventObserver.aidl \
@@ -251,10 +250,13 @@
core/java/android/print/IPrintDocumentAdapterObserver.aidl \
core/java/android/print/IPrintJobStateChangeListener.aidl \
core/java/android/print/IPrintServicesChangeListener.aidl \
+ core/java/android/printservice/recommendation/IRecommendationsChangeListener.aidl \
core/java/android/print/IPrintManager.aidl \
core/java/android/print/IPrintSpooler.aidl \
core/java/android/print/IPrintSpoolerCallbacks.aidl \
core/java/android/print/IPrintSpoolerClient.aidl \
+ core/java/android/printservice/recommendation/IRecommendationServiceCallbacks.aidl \
+ core/java/android/printservice/recommendation/IRecommendationService.aidl \
core/java/android/print/IWriteResultCallback.aidl \
core/java/android/printservice/IPrintService.aidl \
core/java/android/printservice/IPrintServiceClient.aidl \
@@ -300,7 +302,6 @@
core/java/com/android/internal/app/IAssistScreenshotReceiver.aidl \
core/java/com/android/internal/app/IBatteryStats.aidl \
core/java/com/android/internal/app/IEphemeralResolver.aidl \
- core/java/com/android/internal/app/IProcessStats.aidl \
core/java/com/android/internal/app/ISoundTriggerService.aidl \
core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl \
core/java/com/android/internal/app/IVoiceInteractionSessionShowCallback.aidl \
@@ -308,6 +309,7 @@
core/java/com/android/internal/app/IVoiceInteractorCallback.aidl \
core/java/com/android/internal/app/IVoiceInteractorRequest.aidl \
core/java/com/android/internal/app/IMediaContainerService.aidl \
+ core/java/com/android/internal/app/procstats/IProcessStats.aidl \
core/java/com/android/internal/appwidget/IAppWidgetService.aidl \
core/java/com/android/internal/appwidget/IAppWidgetHost.aidl \
core/java/com/android/internal/backup/IBackupTransport.aidl \
@@ -565,6 +567,7 @@
frameworks/base/core/java/android/print/PrintJobInfo.aidl \
frameworks/base/core/java/android/print/PrinterInfo.aidl \
frameworks/base/core/java/android/print/PrintJobId.aidl \
+ frameworks/base/core/java/android/printservice/recommendation/RecommendationInfo.aidl \
frameworks/base/core/java/android/hardware/usb/UsbDevice.aidl \
frameworks/base/core/java/android/hardware/usb/UsbInterface.aidl \
frameworks/base/core/java/android/hardware/usb/UsbEndpoint.aidl \
diff --git a/api/current.txt b/api/current.txt
index f4a1765..e4cc11a 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -71,6 +71,7 @@
field public static final java.lang.String GET_ACCOUNTS = "android.permission.GET_ACCOUNTS";
field public static final java.lang.String GET_ACCOUNTS_PRIVILEGED = "android.permission.GET_ACCOUNTS_PRIVILEGED";
field public static final java.lang.String GET_PACKAGE_SIZE = "android.permission.GET_PACKAGE_SIZE";
+ field public static final java.lang.String GET_PASSWORD_PRIVILEGED = "android.permission.GET_PASSWORD_PRIVILEGED";
field public static final deprecated java.lang.String GET_TASKS = "android.permission.GET_TASKS";
field public static final java.lang.String GLOBAL_SEARCH = "android.permission.GLOBAL_SEARCH";
field public static final java.lang.String INSTALL_LOCATION_PROVIDER = "android.permission.INSTALL_LOCATION_PROVIDER";
@@ -301,13 +302,13 @@
field public static final int backgroundTint = 16843883; // 0x101046b
field public static final int backgroundTintMode = 16843884; // 0x101046c
field public static final int backupAgent = 16843391; // 0x101027f
- field public static final int backupInForeground = 16844060; // 0x101051c
+ field public static final int backupInForeground = 16844059; // 0x101051b
field public static final int banner = 16843762; // 0x10103f2
field public static final int baseline = 16843548; // 0x101031c
field public static final int baselineAlignBottom = 16843042; // 0x1010122
field public static final int baselineAligned = 16843046; // 0x1010126
field public static final int baselineAlignedChildIndex = 16843047; // 0x1010127
- field public static final int bitmap = 16844056; // 0x1010518
+ field public static final int bitmap = 16844055; // 0x1010517
field public static final int borderlessButtonStyle = 16843563; // 0x101032b
field public static final int bottom = 16843184; // 0x10101b0
field public static final int bottomBright = 16842957; // 0x10100cd
@@ -326,7 +327,7 @@
field public static final int buttonBarNeutralButtonStyle = 16843914; // 0x101048a
field public static final int buttonBarPositiveButtonStyle = 16843913; // 0x1010489
field public static final int buttonBarStyle = 16843566; // 0x101032e
- field public static final int buttonGravity = 16844032; // 0x1010500
+ field public static final int buttonGravity = 16844031; // 0x10104ff
field public static final int buttonStyle = 16842824; // 0x1010048
field public static final int buttonStyleInset = 16842826; // 0x101004a
field public static final int buttonStyleSmall = 16842825; // 0x1010049
@@ -337,9 +338,9 @@
field public static final int calendarTextColor = 16843931; // 0x101049b
field public static final int calendarViewShown = 16843596; // 0x101034c
field public static final int calendarViewStyle = 16843613; // 0x101035d
- field public static final int canControlMagnification = 16844041; // 0x1010509
- field public static final int canPerformGestures = 16844047; // 0x101050f
- field public static final int canRecord = 16844062; // 0x101051e
+ field public static final int canControlMagnification = 16844040; // 0x1010508
+ field public static final int canPerformGestures = 16844046; // 0x101050e
+ field public static final int canRecord = 16844061; // 0x101051d
field public static final int canRequestEnhancedWebAccessibility = 16843736; // 0x10103d8
field public static final int canRequestFilterKeyEvents = 16843737; // 0x10103d9
field public static final int canRequestTouchExplorationMode = 16843735; // 0x10103d7
@@ -379,7 +380,7 @@
field public static final int codes = 16843330; // 0x1010242
field public static final int collapseColumns = 16843083; // 0x101014b
field public static final int collapseContentDescription = 16843984; // 0x10104d0
- field public static final int collapseIcon = 16844033; // 0x1010501
+ field public static final int collapseIcon = 16844032; // 0x1010500
field public static final int color = 16843173; // 0x10101a5
field public static final int colorAccent = 16843829; // 0x1010435
field public static final int colorActivatedHighlight = 16843664; // 0x1010390
@@ -416,16 +417,18 @@
field public static final int contentAuthority = 16843408; // 0x1010290
field public static final int contentDescription = 16843379; // 0x1010273
field public static final int contentInsetEnd = 16843860; // 0x1010454
+ field public static final int contentInsetEndWithActions = 16844070; // 0x1010526
field public static final int contentInsetLeft = 16843861; // 0x1010455
field public static final int contentInsetRight = 16843862; // 0x1010456
field public static final int contentInsetStart = 16843859; // 0x1010453
+ field public static final int contentInsetStartWithNavigation = 16844069; // 0x1010525
field public static final int contextClickable = 16844007; // 0x10104e7
- field public static final int contextPopupMenuStyle = 16844035; // 0x1010503
+ field public static final int contextPopupMenuStyle = 16844034; // 0x1010502
field public static final int controlX1 = 16843772; // 0x10103fc
field public static final int controlX2 = 16843774; // 0x10103fe
field public static final int controlY1 = 16843773; // 0x10103fd
field public static final int controlY2 = 16843775; // 0x10103ff
- field public static final int countDown = 16844061; // 0x101051d
+ field public static final int countDown = 16844060; // 0x101051c
field public static final int country = 16843962; // 0x10104ba
field public static final int cropToPadding = 16843043; // 0x1010123
field public static final int cursorVisible = 16843090; // 0x1010152
@@ -443,7 +446,7 @@
field public static final deprecated int dayOfWeekTextAppearance = 16843925; // 0x1010495
field public static final int debuggable = 16842767; // 0x101000f
field public static final int defaultHeight = 16844021; // 0x10104f5
- field public static final int defaultToDeviceProtectedStorage = 16844038; // 0x1010506
+ field public static final int defaultToDeviceProtectedStorage = 16844037; // 0x1010505
field public static final int defaultValue = 16843245; // 0x10101ed
field public static final int defaultWidth = 16844020; // 0x10104f4
field public static final int delay = 16843212; // 0x10101cc
@@ -463,7 +466,7 @@
field public static final int dialogTheme = 16843528; // 0x1010308
field public static final int dialogTitle = 16843250; // 0x10101f2
field public static final int digits = 16843110; // 0x1010166
- field public static final int directBootAware = 16844039; // 0x1010507
+ field public static final int directBootAware = 16844038; // 0x1010506
field public static final int direction = 16843217; // 0x10101d1
field public static final deprecated int directionDescriptions = 16843681; // 0x10103a1
field public static final int directionPriority = 16843218; // 0x10101d2
@@ -514,8 +517,8 @@
field public static final int enabled = 16842766; // 0x101000e
field public static final int end = 16843996; // 0x10104dc
field public static final int endColor = 16843166; // 0x101019e
- field public static final int endX = 16844052; // 0x1010514
- field public static final int endY = 16844053; // 0x1010515
+ field public static final int endX = 16844051; // 0x1010513
+ field public static final int endY = 16844052; // 0x1010514
field public static final deprecated int endYear = 16843133; // 0x101017d
field public static final int enterFadeDuration = 16843532; // 0x101030c
field public static final int entries = 16842930; // 0x10100b2
@@ -535,7 +538,7 @@
field public static final int expandableListViewStyle = 16842863; // 0x101006f
field public static final int expandableListViewWhiteStyle = 16843446; // 0x10102b6
field public static final int exported = 16842768; // 0x1010010
- field public static final int externalService = 16844048; // 0x1010510
+ field public static final int externalService = 16844047; // 0x101050f
field public static final int extraTension = 16843371; // 0x101026b
field public static final int extractNativeLibs = 16844010; // 0x10104ea
field public static final int factor = 16843219; // 0x10101d3
@@ -560,7 +563,7 @@
field public static final int fillBefore = 16843196; // 0x10101bc
field public static final int fillColor = 16843780; // 0x1010404
field public static final int fillEnabled = 16843343; // 0x101024f
- field public static final int fillType = 16844065; // 0x1010521
+ field public static final int fillType = 16844064; // 0x1010520
field public static final int fillViewport = 16843130; // 0x101017a
field public static final int filter = 16843035; // 0x101011b
field public static final int filterTouchesWhenObscured = 16843460; // 0x10102c4
@@ -576,6 +579,7 @@
field public static final int fontFamily = 16843692; // 0x10103ac
field public static final int fontFeatureSettings = 16843959; // 0x10104b7
field public static final int footerDividersEnabled = 16843311; // 0x101022f
+ field public static final int forceHasOverlappingRendering = 16844068; // 0x1010524
field public static final int foreground = 16843017; // 0x1010109
field public static final int foregroundGravity = 16843264; // 0x1010200
field public static final int foregroundTint = 16843885; // 0x101046d
@@ -652,8 +656,8 @@
field public static final int horizontalScrollViewStyle = 16843603; // 0x1010353
field public static final int horizontalSpacing = 16843028; // 0x1010114
field public static final int host = 16842792; // 0x1010028
- field public static final int hotSpotX = 16844057; // 0x1010519
- field public static final int hotSpotY = 16844058; // 0x101051a
+ field public static final int hotSpotX = 16844056; // 0x1010518
+ field public static final int hotSpotY = 16844057; // 0x1010519
field public static final int hyphenationFrequency = 16843998; // 0x10104de
field public static final int icon = 16842754; // 0x1010002
field public static final int iconPreview = 16843337; // 0x1010249
@@ -740,7 +744,7 @@
field public static final int label = 16842753; // 0x1010001
field public static final int labelFor = 16843718; // 0x10103c6
field public static final int labelTextSize = 16843317; // 0x1010235
- field public static final int languageTag = 16844042; // 0x101050a
+ field public static final int languageTag = 16844041; // 0x1010509
field public static final int largeHeap = 16843610; // 0x101035a
field public static final int largeScreens = 16843398; // 0x1010286
field public static final int largestWidthLimitDp = 16843622; // 0x1010366
@@ -798,7 +802,7 @@
field public static final int layout_y = 16843136; // 0x1010180
field public static final int left = 16843181; // 0x10101ad
field public static final int letterSpacing = 16843958; // 0x10104b6
- field public static final int level = 16844034; // 0x1010502
+ field public static final int level = 16844033; // 0x1010501
field public static final int lineSpacingExtra = 16843287; // 0x1010217
field public static final int lineSpacingMultiplier = 16843288; // 0x1010218
field public static final int lines = 16843092; // 0x1010154
@@ -831,7 +835,7 @@
field public static final int marqueeRepeatLimit = 16843293; // 0x101021d
field public static final int matchOrder = 16843855; // 0x101044f
field public static final int max = 16843062; // 0x1010136
- field public static final int maxButtonHeight = 16844031; // 0x10104ff
+ field public static final int maxButtonHeight = 16844030; // 0x10104fe
field public static final int maxDate = 16843584; // 0x1010340
field public static final int maxEms = 16843095; // 0x1010157
field public static final int maxHeight = 16843040; // 0x1010120
@@ -859,7 +863,7 @@
field public static final int minResizeWidth = 16843669; // 0x1010395
field public static final int minSdkVersion = 16843276; // 0x101020c
field public static final int minWidth = 16843071; // 0x101013f
- field public static final int minimalHeight = 16844023; // 0x10104f7
+ field public static final int minimalHeight = 16844067; // 0x1010523
field public static final int minimalWidth = 16844022; // 0x10104f6
field public static final int minimumHorizontalAngle = 16843901; // 0x101047d
field public static final int minimumVerticalAngle = 16843902; // 0x101047e
@@ -881,7 +885,7 @@
field public static final int nextFocusLeft = 16842977; // 0x10100e1
field public static final int nextFocusRight = 16842978; // 0x10100e2
field public static final int nextFocusUp = 16842979; // 0x10100e3
- field public static final int nfcAntennaPositionDrawable = 16844064; // 0x1010520
+ field public static final int nfcAntennaPositionDrawable = 16844063; // 0x101051f
field public static final int noHistory = 16843309; // 0x101022d
field public static final int normalScreens = 16843397; // 0x1010285
field public static final int notificationTimeout = 16843651; // 0x1010383
@@ -893,7 +897,7 @@
field public static final int numbersTextColor = 16843937; // 0x10104a1
field public static final deprecated int numeric = 16843109; // 0x1010165
field public static final int numericShortcut = 16843236; // 0x10101e4
- field public static final int offset = 16844054; // 0x1010516
+ field public static final int offset = 16844053; // 0x1010515
field public static final int onClick = 16843375; // 0x101026f
field public static final int oneshot = 16843159; // 0x1010197
field public static final int opacity = 16843550; // 0x101031e
@@ -940,13 +944,13 @@
field public static final deprecated int phoneNumber = 16843111; // 0x1010167
field public static final int pivotX = 16843189; // 0x10101b5
field public static final int pivotY = 16843190; // 0x10101b6
- field public static final int pointerShape = 16844043; // 0x101050b
+ field public static final int pointerShape = 16844042; // 0x101050a
field public static final int popupAnimationStyle = 16843465; // 0x10102c9
field public static final int popupBackground = 16843126; // 0x1010176
field public static final int popupCharacters = 16843332; // 0x1010244
field public static final int popupElevation = 16843916; // 0x101048c
- field public static final int popupEnterTransition = 16844066; // 0x1010522
- field public static final int popupExitTransition = 16844067; // 0x1010523
+ field public static final int popupEnterTransition = 16844065; // 0x1010521
+ field public static final int popupExitTransition = 16844066; // 0x1010522
field public static final int popupKeyboard = 16843331; // 0x1010243
field public static final int popupLayout = 16843323; // 0x101023b
field public static final int popupMenuStyle = 16843520; // 0x1010300
@@ -955,7 +959,7 @@
field public static final int port = 16842793; // 0x1010029
field public static final int positiveButtonText = 16843253; // 0x10101f5
field public static final int preferenceCategoryStyle = 16842892; // 0x101008c
- field public static final int preferenceFragmentStyle = 16844040; // 0x1010508
+ field public static final int preferenceFragmentStyle = 16844039; // 0x1010507
field public static final int preferenceInformationStyle = 16842893; // 0x101008d
field public static final int preferenceLayoutChild = 16842900; // 0x1010094
field public static final int preferenceScreenStyle = 16842891; // 0x101008b
@@ -1023,7 +1027,7 @@
field public static final int resizeClip = 16843983; // 0x10104cf
field public static final int resizeMode = 16843619; // 0x1010363
field public static final int resizeable = 16843405; // 0x101028d
- field public static final int resizeableActivity = 16844024; // 0x10104f8
+ field public static final int resizeableActivity = 16844023; // 0x10104f7
field public static final int resource = 16842789; // 0x1010025
field public static final int restoreAnyVersion = 16843450; // 0x10102ba
field public static final deprecated int restoreNeedsApplication = 16843421; // 0x101029d
@@ -1143,8 +1147,8 @@
field public static final int startColor = 16843165; // 0x101019d
field public static final int startDelay = 16843746; // 0x10103e2
field public static final int startOffset = 16843198; // 0x10101be
- field public static final int startX = 16844050; // 0x1010512
- field public static final int startY = 16844051; // 0x1010513
+ field public static final int startX = 16844049; // 0x1010511
+ field public static final int startY = 16844050; // 0x1010512
field public static final deprecated int startYear = 16843132; // 0x101017c
field public static final int stateListAnimator = 16843848; // 0x1010448
field public static final int stateNotNeeded = 16842774; // 0x1010016
@@ -1201,8 +1205,8 @@
field public static final int summaryOn = 16843247; // 0x10101ef
field public static final int supportsAssist = 16844016; // 0x10104f0
field public static final int supportsLaunchVoiceAssistFromKeyguard = 16844017; // 0x10104f1
- field public static final int supportsLocalInteraction = 16844049; // 0x1010511
- field public static final int supportsPictureInPicture = 16844025; // 0x10104f9
+ field public static final int supportsLocalInteraction = 16844048; // 0x1010510
+ field public static final int supportsPictureInPicture = 16844024; // 0x10104f8
field public static final int supportsRtl = 16843695; // 0x10103af
field public static final int supportsSwitchingToNextInputMethod = 16843755; // 0x10103eb
field public static final int supportsUploading = 16843419; // 0x101029b
@@ -1251,7 +1255,7 @@
field public static final int textAppearanceListItemSmall = 16843679; // 0x101039f
field public static final int textAppearanceMedium = 16842817; // 0x1010041
field public static final int textAppearanceMediumInverse = 16842820; // 0x1010044
- field public static final int textAppearancePopupMenuHeader = 16844036; // 0x1010504
+ field public static final int textAppearancePopupMenuHeader = 16844035; // 0x1010503
field public static final int textAppearanceSearchResultSubtitle = 16843424; // 0x10102a0
field public static final int textAppearanceSearchResultTitle = 16843425; // 0x10102a1
field public static final int textAppearanceSmall = 16842818; // 0x1010042
@@ -1309,9 +1313,9 @@
field public static final int thumbTint = 16843889; // 0x1010471
field public static final int thumbTintMode = 16843890; // 0x1010472
field public static final int thumbnail = 16843429; // 0x10102a5
- field public static final int tickMark = 16844044; // 0x101050c
- field public static final int tickMarkTint = 16844045; // 0x101050d
- field public static final int tickMarkTintMode = 16844046; // 0x101050e
+ field public static final int tickMark = 16844043; // 0x101050b
+ field public static final int tickMarkTint = 16844044; // 0x101050c
+ field public static final int tickMarkTintMode = 16844045; // 0x101050d
field public static final int tileMode = 16843265; // 0x1010201
field public static final int tileModeX = 16843895; // 0x1010477
field public static final int tileModeY = 16843896; // 0x1010478
@@ -1323,11 +1327,11 @@
field public static final int tintMode = 16843771; // 0x10103fb
field public static final int title = 16843233; // 0x10101e1
field public static final int titleCondensed = 16843234; // 0x10101e2
- field public static final int titleMargin = 16844026; // 0x10104fa
- field public static final int titleMarginBottom = 16844030; // 0x10104fe
- field public static final int titleMarginEnd = 16844028; // 0x10104fc
- field public static final int titleMarginStart = 16844027; // 0x10104fb
- field public static final int titleMarginTop = 16844029; // 0x10104fd
+ field public static final int titleMargin = 16844025; // 0x10104f9
+ field public static final int titleMarginBottom = 16844029; // 0x10104fd
+ field public static final int titleMarginEnd = 16844027; // 0x10104fb
+ field public static final int titleMarginStart = 16844026; // 0x10104fa
+ field public static final int titleMarginTop = 16844028; // 0x10104fc
field public static final int titleTextAppearance = 16843822; // 0x101042e
field public static final int titleTextColor = 16844003; // 0x10104e3
field public static final int titleTextStyle = 16843512; // 0x10102f8
@@ -1366,7 +1370,7 @@
field public static final int trimPathEnd = 16843785; // 0x1010409
field public static final int trimPathOffset = 16843786; // 0x101040a
field public static final int trimPathStart = 16843784; // 0x1010408
- field public static final int tunerCount = 16844063; // 0x101051f
+ field public static final int tunerCount = 16844062; // 0x101051e
field public static final int type = 16843169; // 0x10101a1
field public static final int typeface = 16842902; // 0x1010096
field public static final int uiOptions = 16843672; // 0x1010398
@@ -1374,7 +1378,7 @@
field public static final deprecated int unfocusedMonthDateColor = 16843588; // 0x1010344
field public static final int unselectedAlpha = 16843278; // 0x101020e
field public static final int updatePeriodMillis = 16843344; // 0x1010250
- field public static final int use32bitAbi = 16844055; // 0x1010517
+ field public static final int use32bitAbi = 16844054; // 0x1010516
field public static final int useDefaultMargins = 16843641; // 0x1010379
field public static final int useIntrinsicSizeAsMinimum = 16843536; // 0x1010310
field public static final int useLevel = 16843167; // 0x101019f
@@ -1386,7 +1390,7 @@
field public static final int valueType = 16843488; // 0x10102e0
field public static final int variablePadding = 16843157; // 0x1010195
field public static final int vendor = 16843751; // 0x10103e7
- field public static final int version = 16844059; // 0x101051b
+ field public static final int version = 16844058; // 0x101051a
field public static final int versionCode = 16843291; // 0x101021b
field public static final int versionName = 16843292; // 0x101021c
field public static final int verticalCorrection = 16843322; // 0x101023a
@@ -1430,7 +1434,7 @@
field public static final int windowAllowReturnTransitionOverlap = 16843835; // 0x101043b
field public static final int windowAnimationStyle = 16842926; // 0x10100ae
field public static final int windowBackground = 16842836; // 0x1010054
- field public static final int windowBackgroundFallback = 16844037; // 0x1010505
+ field public static final int windowBackgroundFallback = 16844036; // 0x1010504
field public static final int windowClipToOutline = 16843947; // 0x10104ab
field public static final int windowCloseOnTouchOutside = 16843611; // 0x101035b
field public static final int windowContentOverlay = 16842841; // 0x1010059
@@ -2481,6 +2485,7 @@
field public static final int Widget_Material_CompoundButton_CheckBox = 16974435; // 0x1030263
field public static final int Widget_Material_CompoundButton_RadioButton = 16974436; // 0x1030264
field public static final int Widget_Material_CompoundButton_Star = 16974437; // 0x1030265
+ field public static final int Widget_Material_CompoundButton_Switch = 16974554; // 0x10302da
field public static final int Widget_Material_DatePicker = 16974438; // 0x1030266
field public static final int Widget_Material_DropDownItem = 16974439; // 0x1030267
field public static final int Widget_Material_DropDownItem_Spinner = 16974440; // 0x1030268
@@ -2515,6 +2520,7 @@
field public static final int Widget_Material_Light_CompoundButton_CheckBox = 16974500; // 0x10302a4
field public static final int Widget_Material_Light_CompoundButton_RadioButton = 16974501; // 0x10302a5
field public static final int Widget_Material_Light_CompoundButton_Star = 16974502; // 0x10302a6
+ field public static final int Widget_Material_Light_CompoundButton_Switch = 16974555; // 0x10302db
field public static final int Widget_Material_Light_DatePicker = 16974503; // 0x10302a7
field public static final int Widget_Material_Light_DropDownItem = 16974504; // 0x10302a8
field public static final int Widget_Material_Light_DropDownItem_Spinner = 16974505; // 0x10302a9
@@ -3422,7 +3428,7 @@
method public boolean dispatchTouchEvent(android.view.MotionEvent);
method public boolean dispatchTrackballEvent(android.view.MotionEvent);
method public void dump(java.lang.String, java.io.FileDescriptor, java.io.PrintWriter, java.lang.String[]);
- method public void enterPictureInPicture();
+ method public void enterPictureInPictureMode();
method public android.view.View findViewById(int);
method public void finish();
method public void finishActivity(int);
@@ -3462,15 +3468,16 @@
method public android.view.Window getWindow();
method public android.view.WindowManager getWindowManager();
method public boolean hasWindowFocus();
- method public boolean inMultiWindow();
- method public boolean inPictureInPicture();
method public void invalidateOptionsMenu();
method public boolean isChangingConfigurations();
method public final boolean isChild();
method public boolean isDestroyed();
method public boolean isFinishing();
method public boolean isImmersive();
+ method public boolean isInMultiWindowMode();
+ method public boolean isInPictureInPictureMode();
method public boolean isLocalVoiceInteractionSupported();
+ method public boolean isOverlayWithDecorCaptionEnabled();
method public boolean isTaskRoot();
method public boolean isVoiceInteraction();
method public boolean isVoiceInteractionRoot();
@@ -3517,7 +3524,7 @@
method public void onLowMemory();
method public boolean onMenuItemSelected(int, android.view.MenuItem);
method public boolean onMenuOpened(int, android.view.Menu);
- method public void onMultiWindowChanged(boolean);
+ method public void onMultiWindowModeChanged(boolean);
method public boolean onNavigateUp();
method public boolean onNavigateUpFromChild(android.app.Activity);
method protected void onNewIntent(android.content.Intent);
@@ -3525,7 +3532,7 @@
method public void onOptionsMenuClosed(android.view.Menu);
method public void onPanelClosed(int, android.view.Menu);
method protected void onPause();
- method public void onPictureInPictureChanged(boolean);
+ method public void onPictureInPictureModeChanged(boolean);
method protected void onPostCreate(android.os.Bundle);
method public void onPostCreate(android.os.Bundle, android.os.PersistableBundle);
method protected void onPostResume();
@@ -3563,7 +3570,6 @@
method public android.view.ActionMode onWindowStartingActionMode(android.view.ActionMode.Callback, int);
method public void openContextMenu(android.view.View);
method public void openOptionsMenu();
- method public void overlayWithDecorCaption(boolean);
method public void overridePendingTransition(int, int);
method public void postponeEnterTransition();
method public void recreate();
@@ -3592,6 +3598,7 @@
method public void setImmersive(boolean);
method public void setIntent(android.content.Intent);
method public final void setMediaController(android.media.session.MediaController);
+ method public void setOverlayWithDecorCaptionEnabled(boolean);
method public final deprecated void setProgress(int);
method public final deprecated void setProgressBarIndeterminate(boolean);
method public final deprecated void setProgressBarIndeterminateVisibility(boolean);
@@ -4434,11 +4441,11 @@
method public void onInflate(android.content.Context, android.util.AttributeSet, android.os.Bundle);
method public deprecated void onInflate(android.app.Activity, android.util.AttributeSet, android.os.Bundle);
method public void onLowMemory();
- method public void onMultiWindowChanged(boolean);
+ method public void onMultiWindowModeChanged(boolean);
method public boolean onOptionsItemSelected(android.view.MenuItem);
method public void onOptionsMenuClosed(android.view.Menu);
method public void onPause();
- method public void onPictureInPictureChanged(boolean);
+ method public void onPictureInPictureModeChanged(boolean);
method public void onPrepareOptionsMenu(android.view.Menu);
method public void onRequestPermissionsResult(int, java.lang.String[], int[]);
method public void onResume();
@@ -4519,11 +4526,11 @@
method public void dispatchDestroy();
method public void dispatchDestroyView();
method public void dispatchLowMemory();
- method public void dispatchMultiWindowChanged(boolean);
+ method public void dispatchMultiWindowModeChanged(boolean);
method public boolean dispatchOptionsItemSelected(android.view.MenuItem);
method public void dispatchOptionsMenuClosed(android.view.Menu);
method public void dispatchPause();
- method public void dispatchPictureInPictureChanged(boolean);
+ method public void dispatchPictureInPictureModeChanged(boolean);
method public boolean dispatchPrepareOptionsMenu(android.view.Menu);
method public void dispatchResume();
method public void dispatchStart();
@@ -5751,8 +5758,8 @@
field public static final java.lang.String COMMAND_SECONDARY_TAP = "android.wallpaper.secondaryTap";
field public static final java.lang.String COMMAND_TAP = "android.wallpaper.tap";
field public static final java.lang.String EXTRA_LIVE_WALLPAPER_COMPONENT = "android.service.wallpaper.extra.LIVE_WALLPAPER_COMPONENT";
- field public static final int FLAG_SET_LOCK = 2; // 0x2
- field public static final int FLAG_SET_SYSTEM = 1; // 0x1
+ field public static final int FLAG_LOCK = 2; // 0x2
+ field public static final int FLAG_SYSTEM = 1; // 0x1
field public static final java.lang.String WALLPAPER_PREVIEW_META_DATA = "android.wallpaper.preview";
}
@@ -5852,7 +5859,7 @@
method public boolean getCrossProfileContactsSearchDisabled(android.content.ComponentName);
method public java.util.List<java.lang.String> getCrossProfileWidgetProviders(android.content.ComponentName);
method public int getCurrentFailedPasswordAttempts();
- method public java.lang.String getDeviceOwnerLockScreenInfo();
+ method public java.lang.CharSequence getDeviceOwnerLockScreenInfo();
method public java.util.List<byte[]> getInstalledCaCerts(android.content.ComponentName);
method public int getKeyguardDisabledFeatures(android.content.ComponentName);
method public java.lang.String getLongSupportMessage(android.content.ComponentName);
@@ -5860,7 +5867,6 @@
method public long getMaximumTimeToLock(android.content.ComponentName);
method public int getOrganizationColor(android.content.ComponentName);
method public java.lang.String getOrganizationName(android.content.ComponentName);
- method public boolean getPackageSuspended(android.content.ComponentName, java.lang.String);
method public android.app.admin.DevicePolicyManager getParentProfileInstance(android.content.ComponentName);
method public long getPasswordExpiration(android.content.ComponentName);
method public long getPasswordExpirationTimeout(android.content.ComponentName);
@@ -5890,14 +5896,16 @@
method public boolean hasGrantedPolicy(android.content.ComponentName, int);
method public boolean installCaCert(android.content.ComponentName, byte[]);
method public boolean installKeyPair(android.content.ComponentName, java.security.PrivateKey, java.security.cert.Certificate, java.lang.String);
- method public boolean installKeyPair(android.content.ComponentName, java.security.PrivateKey, java.security.cert.Certificate, java.lang.String, boolean);
+ method public boolean installKeyPair(android.content.ComponentName, java.security.PrivateKey, java.security.cert.Certificate[], java.lang.String, boolean);
method public boolean isActivePasswordSufficient();
method public boolean isAdminActive(android.content.ComponentName);
method public boolean isApplicationHidden(android.content.ComponentName, java.lang.String);
method public boolean isCallerApplicationRestrictionsManagingPackage();
method public boolean isDeviceOwnerApp(java.lang.String);
method public boolean isLockTaskPermitted(java.lang.String);
+ method public boolean isManagedProfile(android.content.ComponentName);
method public boolean isMasterVolumeMuted(android.content.ComponentName);
+ method public boolean isPackageSuspended(android.content.ComponentName, java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
method public boolean isProfileOwnerApp(java.lang.String);
method public boolean isProvisioningAllowed(java.lang.String);
method public boolean isSecurityLoggingEnabled(android.content.ComponentName);
@@ -5923,7 +5931,7 @@
method public void setCertInstallerPackage(android.content.ComponentName, java.lang.String) throws java.lang.SecurityException;
method public void setCrossProfileCallerIdDisabled(android.content.ComponentName, boolean);
method public void setCrossProfileContactsSearchDisabled(android.content.ComponentName, boolean);
- method public boolean setDeviceOwnerLockScreenInfo(android.content.ComponentName, java.lang.String);
+ method public void setDeviceOwnerLockScreenInfo(android.content.ComponentName, java.lang.CharSequence);
method public void setGlobalSetting(android.content.ComponentName, java.lang.String, java.lang.String);
method public boolean setKeyguardDisabled(android.content.ComponentName, boolean);
method public void setKeyguardDisabledFeatures(android.content.ComponentName, int);
@@ -8221,8 +8229,6 @@
method public java.lang.String getPackageResourcePath();
method public android.content.res.Resources getResources();
method public android.content.SharedPreferences getSharedPreferences(java.lang.String, int);
- method public android.content.SharedPreferences getSharedPreferences(java.io.File, int);
- method public java.io.File getSharedPreferencesPath(java.lang.String);
method public java.lang.Object getSystemService(java.lang.String);
method public java.lang.String getSystemServiceName(java.lang.Class<?>);
method public android.content.res.Resources.Theme getTheme();
@@ -8517,8 +8523,9 @@
field public static final java.lang.String ACTION_LOCKED_BOOT_COMPLETED = "android.intent.action.LOCKED_BOOT_COMPLETED";
field public static final java.lang.String ACTION_MAIN = "android.intent.action.MAIN";
field public static final java.lang.String ACTION_MANAGED_PROFILE_ADDED = "android.intent.action.MANAGED_PROFILE_ADDED";
- field public static final java.lang.String ACTION_MANAGED_PROFILE_AVAILABILITY_CHANGED = "android.intent.action.MANAGED_PROFILE_AVAILABILITY_CHANGED";
+ field public static final java.lang.String ACTION_MANAGED_PROFILE_AVAILABLE = "android.intent.action.MANAGED_PROFILE_AVAILABLE";
field public static final java.lang.String ACTION_MANAGED_PROFILE_REMOVED = "android.intent.action.MANAGED_PROFILE_REMOVED";
+ field public static final java.lang.String ACTION_MANAGED_PROFILE_UNAVAILABLE = "android.intent.action.MANAGED_PROFILE_UNAVAILABLE";
field public static final java.lang.String ACTION_MANAGED_PROFILE_UNLOCKED = "android.intent.action.MANAGED_PROFILE_UNLOCKED";
field public static final java.lang.String ACTION_MANAGE_NETWORK_USAGE = "android.intent.action.MANAGE_NETWORK_USAGE";
field public static final java.lang.String ACTION_MANAGE_PACKAGE_STORAGE = "android.intent.action.MANAGE_PACKAGE_STORAGE";
@@ -9913,6 +9920,7 @@
field public static final int PROTECTION_FLAG_PRE23 = 128; // 0x80
field public static final int PROTECTION_FLAG_PREINSTALLED = 1024; // 0x400
field public static final int PROTECTION_FLAG_PRIVILEGED = 16; // 0x10
+ field public static final int PROTECTION_FLAG_SETUP = 2048; // 0x800
field public static final deprecated int PROTECTION_FLAG_SYSTEM = 16; // 0x10
field public static final int PROTECTION_FLAG_VERIFIER = 512; // 0x200
field public static final int PROTECTION_MASK_BASE = 15; // 0xf
@@ -9990,7 +9998,7 @@
field public java.lang.String permission;
}
- public class ShortcutInfo implements android.os.Parcelable {
+ public final class ShortcutInfo implements android.os.Parcelable {
method public int describeContents();
method public android.content.ComponentName getActivityComponent();
method public android.os.PersistableBundle getExtras();
@@ -9998,6 +10006,7 @@
method public android.content.Intent getIntent();
method public long getLastChangedTimestamp();
method public java.lang.String getPackageName();
+ method public java.lang.String getText();
method public java.lang.String getTitle();
method public int getWeight();
method public boolean hasIconFile();
@@ -10025,6 +10034,7 @@
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 android.content.pm.ShortcutInfo.Builder setIntent(android.content.Intent);
+ method public android.content.pm.ShortcutInfo.Builder setText(java.lang.String);
method public android.content.pm.ShortcutInfo.Builder setTitle(java.lang.String);
method public android.content.pm.ShortcutInfo.Builder setWeight(int);
}
@@ -13499,6 +13509,7 @@
public final class Sensor {
method public int getFifoMaxEventCount();
method public int getFifoReservedEventCount();
+ method public int getId();
method public int getMaxDelay();
method public float getMaximumRange();
method public int getMinDelay();
@@ -13508,9 +13519,10 @@
method public float getResolution();
method public java.lang.String getStringType();
method public int getType();
- method public java.util.UUID getUuid();
method public java.lang.String getVendor();
method public int getVersion();
+ method public boolean isAdditionalInfoSupported();
+ method public boolean isDynamicSensor();
method public boolean isWakeUpSensor();
field public static final int REPORTING_MODE_CONTINUOUS = 0; // 0x0
field public static final int REPORTING_MODE_ONE_SHOT = 2; // 0x2
@@ -13629,8 +13641,9 @@
method public static void getRotationMatrixFromVector(float[], float[]);
method public java.util.List<android.hardware.Sensor> getSensorList(int);
method public deprecated int getSensors();
- method public void registerDynamicSensorCallback(android.hardware.SensorManager.DynamicSensorConnectionCallback);
- method public void registerDynamicSensorCallback(android.hardware.SensorManager.DynamicSensorConnectionCallback, android.os.Handler);
+ method public boolean isDynamicSensorDiscoverySupported();
+ method public void registerDynamicSensorCallback(android.hardware.SensorManager.DynamicSensorCallback);
+ method public void registerDynamicSensorCallback(android.hardware.SensorManager.DynamicSensorCallback, android.os.Handler);
method public deprecated boolean registerListener(android.hardware.SensorListener, int);
method public deprecated boolean registerListener(android.hardware.SensorListener, int, int);
method public boolean registerListener(android.hardware.SensorEventListener, android.hardware.Sensor, int);
@@ -13639,7 +13652,7 @@
method public boolean registerListener(android.hardware.SensorEventListener, android.hardware.Sensor, int, int, android.os.Handler);
method public static boolean remapCoordinateSystem(float[], int, int, float[]);
method public boolean requestTriggerSensor(android.hardware.TriggerEventListener, android.hardware.Sensor);
- method public void unregisterDynamicSensorCallback(android.hardware.SensorManager.DynamicSensorConnectionCallback);
+ method public void unregisterDynamicSensorCallback(android.hardware.SensorManager.DynamicSensorCallback);
method public deprecated void unregisterListener(android.hardware.SensorListener);
method public deprecated void unregisterListener(android.hardware.SensorListener, int);
method public void unregisterListener(android.hardware.SensorEventListener, android.hardware.Sensor);
@@ -13704,8 +13717,8 @@
field public static final float STANDARD_GRAVITY = 9.80665f;
}
- public static abstract class SensorManager.DynamicSensorConnectionCallback {
- ctor public SensorManager.DynamicSensorConnectionCallback();
+ public static abstract class SensorManager.DynamicSensorCallback {
+ ctor public SensorManager.DynamicSensorCallback();
method public void onDynamicSensorConnected(android.hardware.Sensor);
method public void onDynamicSensorDisconnected(android.hardware.Sensor);
}
@@ -14830,7 +14843,6 @@
public static abstract interface UCharacter.BidiPairedBracketType {
field public static final int CLOSE = 2; // 0x2
- field public static final int COUNT = 3; // 0x3
field public static final int NONE = 0; // 0x0
field public static final int OPEN = 1; // 0x1
}
@@ -14839,7 +14851,6 @@
field public static final int CANONICAL = 1; // 0x1
field public static final int CIRCLE = 3; // 0x3
field public static final int COMPAT = 2; // 0x2
- field public static final int COUNT = 18; // 0x12
field public static final int FINAL = 4; // 0x4
field public static final int FONT = 5; // 0x5
field public static final int FRACTION = 6; // 0x6
@@ -14859,7 +14870,6 @@
public static abstract interface UCharacter.EastAsianWidth {
field public static final int AMBIGUOUS = 1; // 0x1
- field public static final int COUNT = 6; // 0x6
field public static final int FULLWIDTH = 3; // 0x3
field public static final int HALFWIDTH = 2; // 0x2
field public static final int NARROW = 4; // 0x4
@@ -14869,7 +14879,6 @@
public static abstract interface UCharacter.GraphemeClusterBreak {
field public static final int CONTROL = 1; // 0x1
- field public static final int COUNT = 13; // 0xd
field public static final int CR = 2; // 0x2
field public static final int EXTEND = 3; // 0x3
field public static final int L = 4; // 0x4
@@ -14885,7 +14894,6 @@
}
public static abstract interface UCharacter.HangulSyllableType {
- field public static final int COUNT = 6; // 0x6
field public static final int LEADING_JAMO = 1; // 0x1
field public static final int LVT_SYLLABLE = 5; // 0x5
field public static final int LV_SYLLABLE = 4; // 0x4
@@ -14901,7 +14909,6 @@
field public static final int BEH = 4; // 0x4
field public static final int BETH = 5; // 0x5
field public static final int BURUSHASKI_YEH_BARREE = 54; // 0x36
- field public static final int COUNT = 86; // 0x56
field public static final int DAL = 6; // 0x6
field public static final int DALATH_RISH = 7; // 0x7
field public static final int E = 8; // 0x8
@@ -14986,7 +14993,6 @@
}
public static abstract interface UCharacter.JoiningType {
- field public static final int COUNT = 6; // 0x6
field public static final int DUAL_JOINING = 2; // 0x2
field public static final int JOIN_CAUSING = 1; // 0x1
field public static final int LEFT_JOINING = 3; // 0x3
@@ -15009,7 +15015,6 @@
field public static final int COMPLEX_CONTEXT = 24; // 0x18
field public static final int CONDITIONAL_JAPANESE_STARTER = 37; // 0x25
field public static final int CONTINGENT_BREAK = 7; // 0x7
- field public static final int COUNT = 40; // 0x28
field public static final int EXCLAMATION = 11; // 0xb
field public static final int GLUE = 12; // 0xc
field public static final int H2 = 31; // 0x1f
@@ -15041,7 +15046,6 @@
}
public static abstract interface UCharacter.NumericType {
- field public static final int COUNT = 4; // 0x4
field public static final int DECIMAL = 1; // 0x1
field public static final int DIGIT = 2; // 0x2
field public static final int NONE = 0; // 0x0
@@ -15051,7 +15055,6 @@
public static abstract interface UCharacter.SentenceBreak {
field public static final int ATERM = 1; // 0x1
field public static final int CLOSE = 2; // 0x2
- field public static final int COUNT = 15; // 0xf
field public static final int CR = 11; // 0xb
field public static final int EXTEND = 12; // 0xc
field public static final int FORMAT = 3; // 0x3
@@ -15194,7 +15197,6 @@
field public static final android.icu.lang.UCharacter.UnicodeBlock COPTIC_EPACT_NUMBERS;
field public static final int COPTIC_EPACT_NUMBERS_ID = 223; // 0xdf
field public static final int COPTIC_ID = 132; // 0x84
- field public static final int COUNT = 263; // 0x107
field public static final android.icu.lang.UCharacter.UnicodeBlock COUNTING_ROD_NUMERALS;
field public static final int COUNTING_ROD_NUMERALS_ID = 154; // 0x9a
field public static final android.icu.lang.UCharacter.UnicodeBlock CUNEIFORM;
@@ -15608,7 +15610,6 @@
public static abstract interface UCharacter.WordBreak {
field public static final int ALETTER = 1; // 0x1
- field public static final int COUNT = 17; // 0x11
field public static final int CR = 8; // 0x8
field public static final int DOUBLE_QUOTE = 16; // 0x10
field public static final int EXTEND = 9; // 0x9
@@ -15639,7 +15640,6 @@
}
public static abstract interface UCharacterEnums.ECharacterCategory {
- field public static final byte CHAR_CATEGORY_COUNT = 30; // 0x1e
field public static final byte COMBINING_SPACING_MARK = 8; // 0x8
field public static final byte CONNECTOR_PUNCTUATION = 22; // 0x16
field public static final byte CONTROL = 15; // 0xf
@@ -15679,7 +15679,6 @@
field public static final int ARABIC_NUMBER = 5; // 0x5
field public static final int BLOCK_SEPARATOR = 7; // 0x7
field public static final int BOUNDARY_NEUTRAL = 18; // 0x12
- field public static final int CHAR_DIRECTION_COUNT = 23; // 0x17
field public static final int COMMON_NUMBER_SEPARATOR = 6; // 0x6
field public static final byte DIRECTIONALITY_ARABIC_NUMBER = 5; // 0x5
field public static final byte DIRECTIONALITY_BOUNDARY_NEUTRAL = 18; // 0x12
@@ -15732,7 +15731,6 @@
field public static final int BIDI_MIRRORING_GLYPH = 16385; // 0x4001
field public static final int BIDI_PAIRED_BRACKET = 16397; // 0x400d
field public static final int BIDI_PAIRED_BRACKET_TYPE = 4117; // 0x1015
- field public static final int BINARY_LIMIT = 57; // 0x39
field public static final int BINARY_START = 0; // 0x0
field public static final int BLOCK = 4097; // 0x1001
field public static final int CANONICAL_COMBINING_CLASS = 4098; // 0x1002
@@ -15751,7 +15749,6 @@
field public static final int DEFAULT_IGNORABLE_CODE_POINT = 5; // 0x5
field public static final int DEPRECATED = 6; // 0x6
field public static final int DIACRITIC = 7; // 0x7
- field public static final int DOUBLE_LIMIT = 12289; // 0x3001
field public static final int DOUBLE_START = 12288; // 0x3000
field public static final int EAST_ASIAN_WIDTH = 4100; // 0x1004
field public static final int EXTENDER = 8; // 0x8
@@ -15770,7 +15767,6 @@
field public static final int IDS_TRINARY_OPERATOR = 19; // 0x13
field public static final int ID_CONTINUE = 15; // 0xf
field public static final int ID_START = 16; // 0x10
- field public static final int INT_LIMIT = 4118; // 0x1016
field public static final int INT_START = 4096; // 0x1000
field public static final int JOINING_GROUP = 4102; // 0x1006
field public static final int JOINING_TYPE = 4103; // 0x1007
@@ -15780,7 +15776,6 @@
field public static final int LOGICAL_ORDER_EXCEPTION = 21; // 0x15
field public static final int LOWERCASE = 22; // 0x16
field public static final int LOWERCASE_MAPPING = 16388; // 0x4004
- field public static final int MASK_LIMIT = 8193; // 0x2001
field public static final int MASK_START = 8192; // 0x2000
field public static final int MATH = 23; // 0x17
field public static final int NAME = 16389; // 0x4005
@@ -15795,7 +15790,6 @@
field public static final int NONCHARACTER_CODE_POINT = 24; // 0x18
field public static final int NUMERIC_TYPE = 4105; // 0x1009
field public static final int NUMERIC_VALUE = 12288; // 0x3000
- field public static final int OTHER_PROPERTY_LIMIT = 28673; // 0x7001
field public static final int OTHER_PROPERTY_START = 28672; // 0x7000
field public static final int PATTERN_SYNTAX = 42; // 0x2a
field public static final int PATTERN_WHITE_SPACE = 43; // 0x2b
@@ -15815,7 +15809,6 @@
field public static final int SIMPLE_TITLECASE_MAPPING = 16392; // 0x4008
field public static final int SIMPLE_UPPERCASE_MAPPING = 16393; // 0x4009
field public static final int SOFT_DOTTED = 27; // 0x1b
- field public static final int STRING_LIMIT = 16398; // 0x400e
field public static final int STRING_START = 16384; // 0x4000
field public static final int S_TERM = 35; // 0x23
field public static final int TERMINAL_PUNCTUATION = 28; // 0x1c
@@ -15832,7 +15825,6 @@
}
public static abstract interface UProperty.NameChoice {
- field public static final int COUNT = 2; // 0x2
field public static final int LONG = 1; // 0x1
field public static final int SHORT = 0; // 0x0
}
@@ -15877,7 +15869,6 @@
field public static final int CHAM = 66; // 0x42
field public static final int CHEROKEE = 6; // 0x6
field public static final int CIRTH = 67; // 0x43
- field public static final int CODE_LIMIT = 167; // 0xa7
field public static final int COMMON = 0; // 0x0
field public static final int COPTIC = 7; // 0x7
field public static final int CUNEIFORM = 101; // 0x65
@@ -16272,7 +16263,6 @@
public final class CollationKey implements java.lang.Comparable {
ctor public CollationKey(java.lang.String, byte[]);
- ctor public CollationKey(java.lang.String, android.icu.text.RawCollationKey);
method public int compareTo(android.icu.text.CollationKey);
method public boolean equals(android.icu.text.CollationKey);
method public android.icu.text.CollationKey getBound(int, int);
@@ -16282,7 +16272,6 @@
}
public static final class CollationKey.BoundMode {
- field public static final int COUNT = 3; // 0x3
field public static final int LOWER = 0; // 0x0
field public static final int UPPER = 1; // 0x1
field public static final int UPPER_LONG = 2; // 0x2
@@ -16314,7 +16303,6 @@
method public static final java.lang.String[] getKeywordValuesForLocale(java.lang.String, android.icu.util.ULocale, boolean);
method public static final java.lang.String[] getKeywords();
method public int getMaxVariable();
- method public abstract android.icu.text.RawCollationKey getRawCollationKey(java.lang.String, android.icu.text.RawCollationKey);
method public int[] getReorderCodes();
method public int getStrength();
method public android.icu.text.UnicodeSet getTailoredSet();
@@ -16354,7 +16342,6 @@
field public static final int DEFAULT = -1; // 0xffffffff
field public static final int DIGIT = 4100; // 0x1004
field public static final int FIRST = 4096; // 0x1000
- field public static final int LIMIT = 4101; // 0x1005
field public static final int NONE = 103; // 0x67
field public static final int OTHERS = 103; // 0x67
field public static final int PUNCTUATION = 4097; // 0x1001
@@ -16467,7 +16454,6 @@
field public static final int DOW_LOCAL_FIELD = 19; // 0x13
field public static final int ERA_FIELD = 0; // 0x0
field public static final int EXTENDED_YEAR_FIELD = 20; // 0x14
- field public static final int FIELD_COUNT = 36; // 0x24
field public static final int FRACTIONAL_SECOND_FIELD = 8; // 0x8
field public static final int FULL = 0; // 0x0
field public static final java.lang.String GENERIC_TZ = "vvvv";
@@ -16711,7 +16697,6 @@
field public static final int MONTH = 3; // 0x3
field public static final int QUARTER = 2; // 0x2
field public static final int SECOND = 13; // 0xd
- field public static final int TYPE_LIMIT = 16; // 0x10
field public static final int WEEKDAY = 6; // 0x6
field public static final int WEEK_OF_MONTH = 5; // 0x5
field public static final int WEEK_OF_YEAR = 4; // 0x4
@@ -17342,14 +17327,6 @@
enum_constant public static final android.icu.text.PluralRules.PluralType ORDINAL;
}
- public final class RawCollationKey extends android.icu.util.ByteArrayWrapper {
- ctor public RawCollationKey();
- ctor public RawCollationKey(int);
- ctor public RawCollationKey(byte[]);
- ctor public RawCollationKey(byte[], int);
- method public int compareTo(android.icu.text.RawCollationKey);
- }
-
public final class RelativeDateTimeFormatter {
method public java.lang.String combineDateAndTime(java.lang.String, java.lang.String);
method public java.lang.String format(double, android.icu.text.RelativeDateTimeFormatter.Direction, android.icu.text.RelativeDateTimeFormatter.RelativeUnit);
@@ -17433,7 +17410,6 @@
method public android.icu.text.CollationKey getCollationKey(java.lang.String);
method public void getContractionsAndExpansions(android.icu.text.UnicodeSet, android.icu.text.UnicodeSet, boolean) throws java.lang.Exception;
method public boolean getNumericCollation();
- method public android.icu.text.RawCollationKey getRawCollationKey(java.lang.String, android.icu.text.RawCollationKey);
method public java.lang.String getRules();
method public java.lang.String getRules(boolean);
method public android.icu.util.VersionInfo getUCAVersion();
@@ -17928,19 +17904,6 @@
field public static final int BE = 0; // 0x0
}
- public class ByteArrayWrapper implements java.lang.Comparable {
- ctor public ByteArrayWrapper();
- ctor public ByteArrayWrapper(byte[], int);
- ctor public ByteArrayWrapper(java.nio.ByteBuffer);
- method public final android.icu.util.ByteArrayWrapper append(byte[], int, int);
- method public int compareTo(android.icu.util.ByteArrayWrapper);
- method public android.icu.util.ByteArrayWrapper ensureCapacity(int);
- method public final byte[] releaseBytes();
- method public final android.icu.util.ByteArrayWrapper set(byte[], int, int);
- field public byte[] bytes;
- field public int size;
- }
-
abstract class CECalendar extends android.icu.util.Calendar {
ctor protected CECalendar();
ctor protected CECalendar(android.icu.util.TimeZone);
@@ -19253,10 +19216,19 @@
field public static final int MULTIPATH_INDICATOR_DETECTED = 1; // 0x1
field public static final int MULTIPATH_INDICATOR_NOT_USED = 2; // 0x2
field public static final int MULTIPATH_INDICATOR_UNKNOWN = 0; // 0x0
+ field public static final int STATE_BDS_D2_BIT_SYNC = 256; // 0x100
+ field public static final int STATE_BDS_D2_SUBFRAME_SYNC = 512; // 0x200
field public static final int STATE_BIT_SYNC = 2; // 0x2
field public static final int STATE_CODE_LOCK = 1; // 0x1
+ field public static final int STATE_GAL_E1BC_CODE_LOCK = 1024; // 0x400
+ field public static final int STATE_GAL_E1B_PAGE_SYNC = 4096; // 0x1000
+ field public static final int STATE_GAL_E1C_2ND_CODE_LOCK = 2048; // 0x800
+ field public static final int STATE_GLO_STRING_SYNC = 64; // 0x40
+ field public static final int STATE_GLO_TOD_DECODED = 128; // 0x80
field public static final int STATE_MSEC_AMBIGUOUS = 16; // 0x10
+ field public static final int STATE_SBAS_SYNC = 8192; // 0x2000
field public static final int STATE_SUBFRAME_SYNC = 4; // 0x4
+ field public static final int STATE_SYMBOL_SYNC = 32; // 0x20
field public static final int STATE_TOW_DECODED = 8; // 0x8
field public static final int STATE_UNKNOWN = 0; // 0x0
}
@@ -19843,7 +19815,7 @@
public static abstract class AudioManager.AudioRecordingCallback {
ctor public AudioManager.AudioRecordingCallback();
- method public void onRecordConfigChanged(android.media.AudioRecordingConfiguration[]);
+ method public void onRecordingConfigChanged(android.media.AudioRecordingConfiguration[]);
}
public static abstract interface AudioManager.OnAudioFocusChangeListener {
@@ -20120,6 +20092,7 @@
method public int getAttributeInt(java.lang.String, int);
method public boolean getLatLong(float[]);
method public byte[] getThumbnail();
+ method public long[] getThumbnailRange();
method public boolean hasThumbnail();
method public void saveAttributes() throws java.io.IOException;
method public void setAttribute(java.lang.String, java.lang.String);
@@ -20132,7 +20105,7 @@
field public static final int ORIENTATION_TRANSPOSE = 5; // 0x5
field public static final int ORIENTATION_TRANSVERSE = 7; // 0x7
field public static final int ORIENTATION_UNDEFINED = 0; // 0x0
- field public static final java.lang.String TAG_APERTURE = "FNumber";
+ field public static final deprecated java.lang.String TAG_APERTURE = "FNumber";
field public static final java.lang.String TAG_APERTURE_VALUE = "ApertureValue";
field public static final java.lang.String TAG_ARTIST = "Artist";
field public static final java.lang.String TAG_BITS_PER_SAMPLE = "BitsPerSample";
@@ -20203,7 +20176,7 @@
field public static final java.lang.String TAG_IMAGE_UNIQUE_ID = "ImageUniqueID";
field public static final java.lang.String TAG_IMAGE_WIDTH = "ImageWidth";
field public static final java.lang.String TAG_INTEROPERABILITY_INDEX = "InteroperabilityIndex";
- field public static final java.lang.String TAG_ISO = "ISOSpeedRatings";
+ field public static final deprecated java.lang.String TAG_ISO = "ISOSpeedRatings";
field public static final java.lang.String TAG_ISO_SPEED_RATINGS = "ISOSpeedRatings";
field public static final java.lang.String TAG_JPEG_INTERCHANGE_FORMAT = "JPEGInterchangeFormat";
field public static final java.lang.String TAG_JPEG_INTERCHANGE_FORMAT_LENGTH = "JPEGInterchangeFormatLength";
@@ -20611,12 +20584,13 @@
field public static final int DolbyVisionLevelUhd30 = 64; // 0x40
field public static final int DolbyVisionLevelUhd48 = 128; // 0x80
field public static final int DolbyVisionLevelUhd60 = 256; // 0x100
- field public static final int DolbyVisionProfileDvavDen = 2; // 0x2
- field public static final int DolbyVisionProfileDvavDer = 1; // 0x1
- field public static final int DolbyVisionProfileDvheDen = 4; // 0x4
- field public static final int DolbyVisionProfileDvheDer = 3; // 0x3
- field public static final int DolbyVisionProfileDvheDtr = 5; // 0x5
- field public static final int DolbyVisionProfileDvheStn = 6; // 0x6
+ field public static final int DolbyVisionProfileDvavPen = 2; // 0x2
+ field public static final int DolbyVisionProfileDvavPer = 1; // 0x1
+ field public static final int DolbyVisionProfileDvheDen = 8; // 0x8
+ field public static final int DolbyVisionProfileDvheDer = 4; // 0x4
+ field public static final int DolbyVisionProfileDvheDth = 64; // 0x40
+ field public static final int DolbyVisionProfileDvheDtr = 16; // 0x10
+ field public static final int DolbyVisionProfileDvheStn = 32; // 0x20
field public static final int H263Level10 = 1; // 0x1
field public static final int H263Level20 = 2; // 0x2
field public static final int H263Level30 = 4; // 0x4
@@ -28743,6 +28717,7 @@
field public static final int TEMPERATURE_CURRENT = 0; // 0x0
field public static final int TEMPERATURE_SHUTDOWN = 2; // 0x2
field public static final int TEMPERATURE_THROTTLING = 1; // 0x1
+ field public static final int TEMPERATURE_THROTTLING_BELOW_VR_MIN = 3; // 0x3
field public static final float UNDEFINED_TEMPERATURE = -3.4028235E38f;
}
@@ -29102,6 +29077,7 @@
method public boolean isInteractive();
method public boolean isPowerSaveMode();
method public deprecated boolean isScreenOn();
+ method public boolean isSustainedPerformanceModeSupported();
method public boolean isWakeLockLevelSupported(int);
method public android.os.PowerManager.WakeLock newWakeLock(int, java.lang.String);
method public void reboot(java.lang.String);
@@ -29115,6 +29091,7 @@
field public static final int RELEASE_FLAG_WAIT_FOR_NO_PROXIMITY = 1; // 0x1
field public static final deprecated int SCREEN_BRIGHT_WAKE_LOCK = 10; // 0xa
field public static final deprecated int SCREEN_DIM_WAKE_LOCK = 6; // 0x6
+ field public static final int SUSTAINED_PERFORMANCE_WAKE_LOCK = 256; // 0x100
}
public final class PowerManager.WakeLock {
@@ -29471,7 +29448,7 @@
method public android.os.health.HealthStats[] takeUidSnapshots(int[]);
}
- public class TimerStat implements android.os.Parcelable {
+ public final class TimerStat implements android.os.Parcelable {
ctor public TimerStat();
ctor public TimerStat(int, long);
ctor public TimerStat(android.os.Parcel);
@@ -29727,7 +29704,6 @@
method protected void onClick();
method protected android.view.View onCreateView(android.view.ViewGroup);
method public void onDependencyChanged(android.preference.Preference, boolean);
- method protected void onDetachedFromActivity();
method protected java.lang.Object onGetDefaultValue(android.content.res.TypedArray, int);
method public void onParentChanged(android.preference.Preference, boolean);
method protected void onPrepareForRemoval();
@@ -30358,7 +30334,7 @@
method public final boolean isDestroyed();
method public final boolean isPrinterDiscoveryStarted();
method public abstract void onDestroy();
- method public void onRequestCustomPrinterIcon(android.print.PrinterId, android.printservice.CustomPrinterIconCallback);
+ method public void onRequestCustomPrinterIcon(android.print.PrinterId, android.os.CancellationSignal, android.printservice.CustomPrinterIconCallback);
method public abstract void onStartPrinterDiscovery(java.util.List<android.print.PrinterId>);
method public abstract void onStartPrinterStateTracking(android.print.PrinterId);
method public abstract void onStopPrinterDiscovery();
@@ -30764,6 +30740,7 @@
field public static final int REJECTED_TYPE = 5; // 0x5
field public static final java.lang.String TRANSCRIPTION = "transcription";
field public static final java.lang.String TYPE = "type";
+ field public static final java.lang.String VIA_NUMBER = "via_number";
field public static final int VOICEMAIL_TYPE = 4; // 0x4
field public static final java.lang.String VOICEMAIL_URI = "voicemail_uri";
}
@@ -31914,6 +31891,7 @@
field public static final java.lang.String EXTRA_EXCLUDE_SELF = "android.provider.extra.EXCLUDE_SELF";
field public static final java.lang.String EXTRA_INFO = "info";
field public static final java.lang.String EXTRA_LOADING = "loading";
+ field public static final java.lang.String EXTRA_ORIENTATION = "android.provider.extra.ORIENTATION";
field public static final java.lang.String EXTRA_PROMPT = "android.provider.extra.PROMPT";
field public static final java.lang.String PROVIDER_INTERFACE = "android.content.action.DOCUMENTS_PROVIDER";
}
@@ -36755,6 +36733,7 @@
field public static final java.lang.String KEY_CARRIER_VT_AVAILABLE_BOOL = "carrier_vt_available_bool";
field public static final java.lang.String KEY_CARRIER_VVM_PACKAGE_NAME_STRING = "carrier_vvm_package_name_string";
field public static final java.lang.String KEY_CARRIER_WFC_IMS_AVAILABLE_BOOL = "carrier_wfc_ims_available_bool";
+ field public static final java.lang.String KEY_CARRIER_WFC_SUPPORTS_WIFI_ONLY_BOOL = "carrier_wfc_supports_wifi_only_bool";
field public static final java.lang.String KEY_CDMA_DTMF_TONE_DELAY_INT = "cdma_dtmf_tone_delay_int";
field public static final java.lang.String KEY_CDMA_NONROAMING_NETWORKS_STRING_ARRAY = "cdma_nonroaming_networks_string_array";
field public static final java.lang.String KEY_CDMA_ROAMING_NETWORKS_STRING_ARRAY = "cdma_roaming_networks_string_array";
@@ -37331,7 +37310,8 @@
method public java.lang.String getDeviceSoftwareVersion();
method public java.lang.String getGroupIdLevel1();
method public java.lang.String getGroupIdLevel1(int);
- method public java.lang.String getIccSimChallengeResponse(int, java.lang.String);
+ method public java.lang.String getIccAuthentication(int, int, java.lang.String);
+ method public java.lang.String getIccAuthentication(int, int, int, java.lang.String);
method public java.lang.String getLine1AlphaTag(int);
method public java.lang.String getLine1Number();
method public java.lang.String getLine1Number(int);
@@ -37400,6 +37380,13 @@
field public static final java.lang.String ACTION_CONFIGURE_VOICEMAIL = "android.telephony.action.CONFIGURE_VOICEMAIL";
field public static final java.lang.String ACTION_PHONE_STATE_CHANGED = "android.intent.action.PHONE_STATE";
field public static final java.lang.String ACTION_RESPOND_VIA_MESSAGE = "android.intent.action.RESPOND_VIA_MESSAGE";
+ field public static final int APPTYPE_CSIM = 4; // 0x4
+ field public static final int APPTYPE_ISIM = 5; // 0x5
+ field public static final int APPTYPE_RUIM = 3; // 0x3
+ field public static final int APPTYPE_SIM = 1; // 0x1
+ field public static final int APPTYPE_USIM = 2; // 0x2
+ field public static final int AUTHTYPE_EAP_AKA = 129; // 0x81
+ field public static final int AUTHTYPE_EAP_SIM = 128; // 0x80
field public static final int CALL_STATE_IDLE = 0; // 0x0
field public static final int CALL_STATE_OFFHOOK = 2; // 0x2
field public static final int CALL_STATE_RINGING = 1; // 0x1
@@ -37943,8 +37930,6 @@
method public java.lang.String getPackageResourcePath();
method public android.content.res.Resources getResources();
method public android.content.SharedPreferences getSharedPreferences(java.lang.String, int);
- method public android.content.SharedPreferences getSharedPreferences(java.io.File, int);
- method public java.io.File getSharedPreferencesPath(java.lang.String);
method public java.lang.Object getSystemService(java.lang.String);
method public java.lang.String getSystemServiceName(java.lang.Class<?>);
method public android.content.res.Resources.Theme getTheme();
@@ -42299,6 +42284,7 @@
method public boolean dispatchDragEvent(android.view.DragEvent);
method protected void dispatchDraw(android.graphics.Canvas);
method public void dispatchDrawableHotspotChanged(float, float);
+ method public void dispatchFinishTemporaryDetach();
method protected boolean dispatchGenericFocusedEvent(android.view.MotionEvent);
method public boolean dispatchGenericMotionEvent(android.view.MotionEvent);
method protected boolean dispatchGenericPointerEvent(android.view.MotionEvent);
@@ -42318,6 +42304,7 @@
method protected void dispatchSetActivated(boolean);
method protected void dispatchSetPressed(boolean);
method protected void dispatchSetSelected(boolean);
+ method public void dispatchStartTemporaryDetach();
method public void dispatchSystemUiVisibilityChanged(int);
method public boolean dispatchTouchEvent(android.view.MotionEvent);
method public boolean dispatchTrackballEvent(android.view.MotionEvent);
@@ -42335,6 +42322,7 @@
method public void findViewsWithText(java.util.ArrayList<android.view.View>, java.lang.CharSequence, int);
method protected deprecated boolean fitSystemWindows(android.graphics.Rect);
method public android.view.View focusSearch(int);
+ method public void forceHasOverlappingRendering(boolean);
method public void forceLayout();
method public static int generateViewId();
method public java.lang.CharSequence getAccessibilityClassName();
@@ -42380,6 +42368,7 @@
method public boolean getGlobalVisibleRect(android.graphics.Rect, android.graphics.Point);
method public final boolean getGlobalVisibleRect(android.graphics.Rect);
method public android.os.Handler getHandler();
+ method public final boolean getHasOverlappingRendering();
method public final int getHeight();
method public void getHitRect(android.graphics.Rect);
method public int getHorizontalFadingEdgeLength();
@@ -42528,6 +42517,7 @@
method public boolean isSelected();
method public boolean isShown();
method public boolean isSoundEffectsEnabled();
+ method public final boolean isTemporarilyDetached();
method public boolean isTextAlignmentResolved();
method public boolean isTextDirectionResolved();
method public boolean isVerticalFadingEdgeEnabled();
@@ -44284,6 +44274,7 @@
public final class AccessibilityWindowInfo implements android.os.Parcelable {
method public int describeContents();
+ method public android.view.accessibility.AccessibilityNodeInfo getAnchor();
method public void getBoundsInScreen(android.graphics.Rect);
method public android.view.accessibility.AccessibilityWindowInfo getChild(int);
method public int getChildCount();
@@ -44291,6 +44282,7 @@
method public int getLayer();
method public android.view.accessibility.AccessibilityWindowInfo getParent();
method public android.view.accessibility.AccessibilityNodeInfo getRoot();
+ method public java.lang.CharSequence getTitle();
method public int getType();
method public boolean isAccessibilityFocused();
method public boolean isActive();
@@ -44631,6 +44623,7 @@
ctor public BaseInputConnection(android.view.View, boolean);
method public boolean beginBatchEdit();
method public boolean clearMetaKeyStates(int);
+ method public void closeConnection();
method public boolean commitCompletion(android.view.inputmethod.CompletionInfo);
method public boolean commitCorrection(android.view.inputmethod.CorrectionInfo);
method public boolean commitText(java.lang.CharSequence, int);
@@ -44798,6 +44791,7 @@
public abstract interface InputConnection {
method public abstract boolean beginBatchEdit();
method public abstract boolean clearMetaKeyStates(int);
+ method public abstract void closeConnection();
method public abstract boolean commitCompletion(android.view.inputmethod.CompletionInfo);
method public abstract boolean commitCorrection(android.view.inputmethod.CorrectionInfo);
method public abstract boolean commitText(java.lang.CharSequence, int);
@@ -44830,6 +44824,7 @@
ctor public InputConnectionWrapper(android.view.inputmethod.InputConnection, boolean);
method public boolean beginBatchEdit();
method public boolean clearMetaKeyStates(int);
+ method public void closeConnection();
method public boolean commitCompletion(android.view.inputmethod.CompletionInfo);
method public boolean commitCorrection(android.view.inputmethod.CorrectionInfo);
method public boolean commitText(java.lang.CharSequence, int);
@@ -48277,9 +48272,15 @@
method public void collapseActionView();
method public void dismissPopupMenus();
method public int getContentInsetEnd();
+ method public int getContentInsetEndWithActions();
method public int getContentInsetLeft();
method public int getContentInsetRight();
method public int getContentInsetStart();
+ method public int getContentInsetStartWithNavigation();
+ method public int getCurrentContentInsetEnd();
+ method public int getCurrentContentInsetLeft();
+ method public int getCurrentContentInsetRight();
+ method public int getCurrentContentInsetStart();
method public android.graphics.drawable.Drawable getLogo();
method public java.lang.CharSequence getLogoDescription();
method public android.view.Menu getMenu();
@@ -48298,6 +48299,8 @@
method public void inflateMenu(int);
method public boolean isOverflowMenuShowing();
method protected void onLayout(boolean, int, int, int, int);
+ method public void setContentInsetEndWithActions(int);
+ method public void setContentInsetStartWithNavigation(int);
method public void setContentInsetsAbsolute(int, int);
method public void setContentInsetsRelative(int, int);
method public void setLogo(int);
@@ -49282,9 +49285,7 @@
public final class FilePermission extends java.security.Permission implements java.io.Serializable {
ctor public FilePermission(java.lang.String, java.lang.String);
- method public boolean equals(java.lang.Object);
method public java.lang.String getActions();
- method public int hashCode();
method public boolean implies(java.security.Permission);
}
@@ -50023,6 +50024,7 @@
method public static int compare(boolean, boolean);
method public int compareTo(java.lang.Boolean);
method public static boolean getBoolean(java.lang.String);
+ method public static int hashCode(boolean);
method public static boolean parseBoolean(java.lang.String);
method public static java.lang.String toString(boolean);
method public static java.lang.Boolean valueOf(boolean);
@@ -50040,6 +50042,7 @@
method public static java.lang.Byte decode(java.lang.String) throws java.lang.NumberFormatException;
method public double doubleValue();
method public float floatValue();
+ method public static int hashCode(byte);
method public int intValue();
method public long longValue();
method public static byte parseByte(java.lang.String, int) throws java.lang.NumberFormatException;
@@ -50048,6 +50051,7 @@
method public static java.lang.Byte valueOf(byte);
method public static java.lang.Byte valueOf(java.lang.String, int) throws java.lang.NumberFormatException;
method public static java.lang.Byte valueOf(java.lang.String) throws java.lang.NumberFormatException;
+ field public static final int BYTES = 1; // 0x1
field public static final byte MAX_VALUE = 127; // 0x7f
field public static final byte MIN_VALUE = -128; // 0xffffff80
field public static final int SIZE = 8; // 0x8
@@ -50085,6 +50089,7 @@
method public static int getNumericValue(int);
method public static int getType(char);
method public static int getType(int);
+ method public static int hashCode(char);
method public static char highSurrogate(int);
method public static boolean isAlphabetic(int);
method public static boolean isBmpCodePoint(int);
@@ -50145,6 +50150,7 @@
method public static char toUpperCase(char);
method public static int toUpperCase(int);
method public static java.lang.Character valueOf(char);
+ field public static final int BYTES = 2; // 0x2
field public static final byte COMBINING_SPACING_MARK = 8; // 0x8
field public static final byte CONNECTOR_PUNCTUATION = 23; // 0x17
field public static final byte CONTROL = 15; // 0xf
@@ -50771,6 +50777,7 @@
method public static int floatToIntBits(float);
method public static int floatToRawIntBits(float);
method public float floatValue();
+ method public static int hashCode(float);
method public static float intBitsToFloat(int);
method public int intValue();
method public static boolean isFinite(float);
@@ -50779,11 +50786,15 @@
method public static boolean isNaN(float);
method public boolean isNaN();
method public long longValue();
+ method public static float max(float, float);
+ method public static float min(float, float);
method public static float parseFloat(java.lang.String) throws java.lang.NumberFormatException;
+ method public static float sum(float, float);
method public static java.lang.String toHexString(float);
method public static java.lang.String toString(float);
method public static java.lang.Float valueOf(java.lang.String) throws java.lang.NumberFormatException;
method public static java.lang.Float valueOf(float);
+ field public static final int BYTES = 4; // 0x4
field public static final int MAX_EXPONENT = 127; // 0x7f
field public static final float MAX_VALUE = 3.4028235E38f;
field public static final int MIN_EXPONENT = -126; // 0xffffff82
@@ -50963,6 +50974,7 @@
method public static java.lang.Long valueOf(java.lang.String, int) throws java.lang.NumberFormatException;
method public static java.lang.Long valueOf(java.lang.String) throws java.lang.NumberFormatException;
method public static java.lang.Long valueOf(long);
+ field public static final int BYTES = 8; // 0x8
field public static final long MAX_VALUE = 9223372036854775807L; // 0x7fffffffffffffffL
field public static final long MIN_VALUE = -9223372036854775808L; // 0x8000000000000000L
field public static final int SIZE = 64; // 0x40
@@ -51266,6 +51278,7 @@
method public static java.lang.Short decode(java.lang.String) throws java.lang.NumberFormatException;
method public double doubleValue();
method public float floatValue();
+ method public static int hashCode(short);
method public int intValue();
method public long longValue();
method public static short parseShort(java.lang.String, int) throws java.lang.NumberFormatException;
@@ -51275,6 +51288,7 @@
method public static java.lang.Short valueOf(java.lang.String, int) throws java.lang.NumberFormatException;
method public static java.lang.Short valueOf(java.lang.String) throws java.lang.NumberFormatException;
method public static java.lang.Short valueOf(short);
+ field public static final int BYTES = 2; // 0x2
field public static final short MAX_VALUE = 32767; // 0x7fff
field public static final short MIN_VALUE = -32768; // 0xffff8000
field public static final int SIZE = 16; // 0x10
@@ -52798,9 +52812,7 @@
public final class SocketPermission extends java.security.Permission implements java.io.Serializable {
ctor public SocketPermission(java.lang.String, java.lang.String);
- method public boolean equals(java.lang.Object);
method public java.lang.String getActions();
- method public int hashCode();
method public boolean implies(java.security.Permission);
}
@@ -53882,9 +53894,7 @@
public final class AllPermission extends java.security.Permission {
ctor public AllPermission();
ctor public AllPermission(java.lang.String, java.lang.String);
- method public boolean equals(java.lang.Object);
method public java.lang.String getActions();
- method public int hashCode();
method public boolean implies(java.security.Permission);
}
@@ -53898,9 +53908,7 @@
public abstract class BasicPermission extends java.security.Permission implements java.io.Serializable {
ctor public BasicPermission(java.lang.String);
ctor public BasicPermission(java.lang.String, java.lang.String);
- method public boolean equals(java.lang.Object);
method public java.lang.String getActions();
- method public int hashCode();
method public boolean implies(java.security.Permission);
}
@@ -54278,10 +54286,8 @@
public abstract class Permission implements java.security.Guard java.io.Serializable {
ctor public Permission(java.lang.String);
method public void checkGuard(java.lang.Object) throws java.lang.SecurityException;
- method public abstract boolean equals(java.lang.Object);
method public abstract java.lang.String getActions();
method public final java.lang.String getName();
- method public abstract int hashCode();
method public abstract boolean implies(java.security.Permission);
method public java.security.PermissionCollection newPermissionCollection();
}
@@ -54539,13 +54545,11 @@
public final class UnresolvedPermission extends java.security.Permission implements java.io.Serializable {
ctor public UnresolvedPermission(java.lang.String, java.lang.String, java.lang.String, java.security.cert.Certificate[]);
- method public boolean equals(java.lang.Object);
method public java.lang.String getActions();
method public java.lang.String getUnresolvedActions();
method public java.security.cert.Certificate[] getUnresolvedCerts();
method public java.lang.String getUnresolvedName();
method public java.lang.String getUnresolvedType();
- method public int hashCode();
method public boolean implies(java.security.Permission);
}
@@ -54603,8 +54607,6 @@
}
public abstract interface Permission {
- method public abstract boolean equals(java.lang.Object);
- method public abstract java.lang.String toString();
}
}
@@ -57320,6 +57322,7 @@
method public void forEach(java.util.function.Consumer<? super E>);
method public E get(int);
method public boolean removeIf(java.util.function.Predicate<? super E>);
+ method public void replaceAll(java.util.function.UnaryOperator<E>);
method public int size();
method public void sort(java.util.Comparator<? super E>);
method public java.util.Spliterator<E> spliterator();
@@ -57405,6 +57408,10 @@
method public static int hashCode(float[]);
method public static int hashCode(double[]);
method public static int hashCode(java.lang.Object[]);
+ method public static void parallelSetAll(T[], java.util.function.IntFunction<? extends T>);
+ method public static void parallelSetAll(int[], java.util.function.IntUnaryOperator);
+ method public static void parallelSetAll(long[], java.util.function.IntToLongFunction);
+ method public static void parallelSetAll(double[], java.util.function.IntToDoubleFunction);
method public static void parallelSort(byte[]);
method public static void parallelSort(byte[], int, int);
method public static void parallelSort(char[]);
@@ -57953,6 +57960,7 @@
method public java.lang.Object clone();
method public java.util.Set<java.util.Map.Entry<K, V>> entrySet();
method public void forEach(java.util.function.BiConsumer<? super K, ? super V>);
+ method public boolean replace(K, V, V);
}
public class HashSet extends java.util.AbstractSet implements java.lang.Cloneable java.io.Serializable java.util.Set {
@@ -57973,6 +57981,9 @@
ctor public Hashtable(java.util.Map<? extends K, ? extends V>);
method public synchronized void clear();
method public synchronized java.lang.Object clone();
+ method public synchronized V compute(K, java.util.function.BiFunction<? super K, ? super V, ? extends V>);
+ method public synchronized V computeIfAbsent(K, java.util.function.Function<? super K, ? extends V>);
+ method public synchronized V computeIfPresent(K, java.util.function.BiFunction<? super K, ? super V, ? extends V>);
method public synchronized boolean contains(java.lang.Object);
method public synchronized boolean containsKey(java.lang.Object);
method public boolean containsValue(java.lang.Object);
@@ -57980,13 +57991,19 @@
method public java.util.Set<java.util.Map.Entry<K, V>> entrySet();
method public synchronized void forEach(java.util.function.BiConsumer<? super K, ? super V>);
method public synchronized V get(java.lang.Object);
+ method public synchronized V getOrDefault(java.lang.Object, V);
method public synchronized boolean isEmpty();
method public java.util.Set<K> keySet();
method public synchronized java.util.Enumeration<K> keys();
+ method public synchronized V merge(K, V, java.util.function.BiFunction<? super V, ? super V, ? extends V>);
method public synchronized V put(K, V);
method public synchronized void putAll(java.util.Map<? extends K, ? extends V>);
+ method public synchronized V putIfAbsent(K, V);
method protected void rehash();
method public synchronized V remove(java.lang.Object);
+ method public synchronized boolean remove(java.lang.Object, java.lang.Object);
+ method public synchronized boolean replace(K, V, V);
+ method public synchronized V replace(K, V);
method public synchronized int size();
method public java.util.Collection<V> values();
}
@@ -58131,9 +58148,11 @@
method public abstract boolean remove(java.lang.Object);
method public abstract E remove(int);
method public abstract boolean removeAll(java.util.Collection<?>);
+ method public default void replaceAll(java.util.function.UnaryOperator<E>);
method public abstract boolean retainAll(java.util.Collection<?>);
method public abstract E set(int, E);
method public abstract int size();
+ method public default void sort(java.util.Comparator<? super E>);
method public abstract java.util.List<E> subList(int, int);
method public abstract java.lang.Object[] toArray();
method public abstract T[] toArray(T[]);
@@ -59048,9 +59067,11 @@
method public synchronized boolean removeElement(java.lang.Object);
method public synchronized void removeElementAt(int);
method public synchronized boolean removeIf(java.util.function.Predicate<? super E>);
+ method public synchronized void replaceAll(java.util.function.UnaryOperator<E>);
method public synchronized void setElementAt(E, int);
method public synchronized void setSize(int);
method public synchronized int size();
+ method public synchronized void sort(java.util.Comparator<? super E>);
method public java.util.Spliterator<E> spliterator();
method public synchronized void trimToSize();
field protected int capacityIncrement;
@@ -59516,6 +59537,7 @@
method public java.lang.Object clone();
method public boolean contains(java.lang.Object);
method public boolean containsAll(java.util.Collection<?>);
+ method public void forEach(java.util.function.Consumer<? super E>);
method public E get(int);
method public int indexOf(E, int);
method public int indexOf(java.lang.Object);
@@ -63893,11 +63915,9 @@
public final class PrivateCredentialPermission extends java.security.Permission {
ctor public PrivateCredentialPermission(java.lang.String, java.lang.String);
- method public boolean equals(java.lang.Object);
method public java.lang.String getActions();
method public java.lang.String getCredentialClass();
method public java.lang.String[][] getPrincipals();
- method public int hashCode();
method public boolean implies(java.security.Permission);
}
diff --git a/api/removed.txt b/api/removed.txt
index 86085c8..3f16bca 100644
--- a/api/removed.txt
+++ b/api/removed.txt
@@ -94,6 +94,10 @@
package android.media.tv {
+ public final class TvInputManager {
+ method public android.media.tv.TvInputManager.Hardware acquireTvInputHardware(int, android.media.tv.TvInputManager.HardwareCallback, android.media.tv.TvInputInfo);
+ }
+
public class TvView extends android.view.ViewGroup {
method public void requestUnblockContent(android.media.tv.TvContentRating);
}
diff --git a/api/system-current.txt b/api/system-current.txt
index 8fe8c12..f63d2ac 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -42,6 +42,7 @@
field public static final java.lang.String BIND_MIDI_DEVICE_SERVICE = "android.permission.BIND_MIDI_DEVICE_SERVICE";
field public static final java.lang.String BIND_NFC_SERVICE = "android.permission.BIND_NFC_SERVICE";
field public static final java.lang.String BIND_NOTIFICATION_LISTENER_SERVICE = "android.permission.BIND_NOTIFICATION_LISTENER_SERVICE";
+ field public static final java.lang.String BIND_PRINT_RECOMMENDATION_SERVICE = "android.permission.BIND_PRINT_RECOMMENDATION_SERVICE";
field public static final java.lang.String BIND_PRINT_SERVICE = "android.permission.BIND_PRINT_SERVICE";
field public static final java.lang.String BIND_QUICK_SETTINGS_TILE = "android.permission.BIND_QUICK_SETTINGS_TILE";
field public static final java.lang.String BIND_REMOTEVIEWS = "android.permission.BIND_REMOTEVIEWS";
@@ -102,6 +103,7 @@
field public static final java.lang.String GET_APP_OPS_STATS = "android.permission.GET_APP_OPS_STATS";
field public static final java.lang.String GET_PACKAGE_IMPORTANCE = "android.permission.GET_PACKAGE_IMPORTANCE";
field public static final java.lang.String GET_PACKAGE_SIZE = "android.permission.GET_PACKAGE_SIZE";
+ field public static final java.lang.String GET_PASSWORD_PRIVILEGED = "android.permission.GET_PASSWORD_PRIVILEGED";
field public static final java.lang.String GET_PROCESS_STATE_AND_OOM_SCORE = "android.permission.GET_PROCESS_STATE_AND_OOM_SCORE";
field public static final deprecated java.lang.String GET_TASKS = "android.permission.GET_TASKS";
field public static final java.lang.String GET_TOP_ACTIVITY_INFO = "android.permission.GET_TOP_ACTIVITY_INFO";
@@ -396,13 +398,13 @@
field public static final int backgroundTint = 16843883; // 0x101046b
field public static final int backgroundTintMode = 16843884; // 0x101046c
field public static final int backupAgent = 16843391; // 0x101027f
- field public static final int backupInForeground = 16844060; // 0x101051c
+ field public static final int backupInForeground = 16844059; // 0x101051b
field public static final int banner = 16843762; // 0x10103f2
field public static final int baseline = 16843548; // 0x101031c
field public static final int baselineAlignBottom = 16843042; // 0x1010122
field public static final int baselineAligned = 16843046; // 0x1010126
field public static final int baselineAlignedChildIndex = 16843047; // 0x1010127
- field public static final int bitmap = 16844056; // 0x1010518
+ field public static final int bitmap = 16844055; // 0x1010517
field public static final int borderlessButtonStyle = 16843563; // 0x101032b
field public static final int bottom = 16843184; // 0x10101b0
field public static final int bottomBright = 16842957; // 0x10100cd
@@ -421,7 +423,7 @@
field public static final int buttonBarNeutralButtonStyle = 16843914; // 0x101048a
field public static final int buttonBarPositiveButtonStyle = 16843913; // 0x1010489
field public static final int buttonBarStyle = 16843566; // 0x101032e
- field public static final int buttonGravity = 16844032; // 0x1010500
+ field public static final int buttonGravity = 16844031; // 0x10104ff
field public static final int buttonStyle = 16842824; // 0x1010048
field public static final int buttonStyleInset = 16842826; // 0x101004a
field public static final int buttonStyleSmall = 16842825; // 0x1010049
@@ -432,9 +434,9 @@
field public static final int calendarTextColor = 16843931; // 0x101049b
field public static final int calendarViewShown = 16843596; // 0x101034c
field public static final int calendarViewStyle = 16843613; // 0x101035d
- field public static final int canControlMagnification = 16844041; // 0x1010509
- field public static final int canPerformGestures = 16844047; // 0x101050f
- field public static final int canRecord = 16844062; // 0x101051e
+ field public static final int canControlMagnification = 16844040; // 0x1010508
+ field public static final int canPerformGestures = 16844046; // 0x101050e
+ field public static final int canRecord = 16844061; // 0x101051d
field public static final int canRequestEnhancedWebAccessibility = 16843736; // 0x10103d8
field public static final int canRequestFilterKeyEvents = 16843737; // 0x10103d9
field public static final int canRequestTouchExplorationMode = 16843735; // 0x10103d7
@@ -474,7 +476,7 @@
field public static final int codes = 16843330; // 0x1010242
field public static final int collapseColumns = 16843083; // 0x101014b
field public static final int collapseContentDescription = 16843984; // 0x10104d0
- field public static final int collapseIcon = 16844033; // 0x1010501
+ field public static final int collapseIcon = 16844032; // 0x1010500
field public static final int color = 16843173; // 0x10101a5
field public static final int colorAccent = 16843829; // 0x1010435
field public static final int colorActivatedHighlight = 16843664; // 0x1010390
@@ -511,16 +513,18 @@
field public static final int contentAuthority = 16843408; // 0x1010290
field public static final int contentDescription = 16843379; // 0x1010273
field public static final int contentInsetEnd = 16843860; // 0x1010454
+ field public static final int contentInsetEndWithActions = 16844070; // 0x1010526
field public static final int contentInsetLeft = 16843861; // 0x1010455
field public static final int contentInsetRight = 16843862; // 0x1010456
field public static final int contentInsetStart = 16843859; // 0x1010453
+ field public static final int contentInsetStartWithNavigation = 16844069; // 0x1010525
field public static final int contextClickable = 16844007; // 0x10104e7
- field public static final int contextPopupMenuStyle = 16844035; // 0x1010503
+ field public static final int contextPopupMenuStyle = 16844034; // 0x1010502
field public static final int controlX1 = 16843772; // 0x10103fc
field public static final int controlX2 = 16843774; // 0x10103fe
field public static final int controlY1 = 16843773; // 0x10103fd
field public static final int controlY2 = 16843775; // 0x10103ff
- field public static final int countDown = 16844061; // 0x101051d
+ field public static final int countDown = 16844060; // 0x101051c
field public static final int country = 16843962; // 0x10104ba
field public static final int cropToPadding = 16843043; // 0x1010123
field public static final int cursorVisible = 16843090; // 0x1010152
@@ -538,7 +542,7 @@
field public static final deprecated int dayOfWeekTextAppearance = 16843925; // 0x1010495
field public static final int debuggable = 16842767; // 0x101000f
field public static final int defaultHeight = 16844021; // 0x10104f5
- field public static final int defaultToDeviceProtectedStorage = 16844038; // 0x1010506
+ field public static final int defaultToDeviceProtectedStorage = 16844037; // 0x1010505
field public static final int defaultValue = 16843245; // 0x10101ed
field public static final int defaultWidth = 16844020; // 0x10104f4
field public static final int delay = 16843212; // 0x10101cc
@@ -558,7 +562,7 @@
field public static final int dialogTheme = 16843528; // 0x1010308
field public static final int dialogTitle = 16843250; // 0x10101f2
field public static final int digits = 16843110; // 0x1010166
- field public static final int directBootAware = 16844039; // 0x1010507
+ field public static final int directBootAware = 16844038; // 0x1010506
field public static final int direction = 16843217; // 0x10101d1
field public static final deprecated int directionDescriptions = 16843681; // 0x10103a1
field public static final int directionPriority = 16843218; // 0x10101d2
@@ -609,8 +613,8 @@
field public static final int enabled = 16842766; // 0x101000e
field public static final int end = 16843996; // 0x10104dc
field public static final int endColor = 16843166; // 0x101019e
- field public static final int endX = 16844052; // 0x1010514
- field public static final int endY = 16844053; // 0x1010515
+ field public static final int endX = 16844051; // 0x1010513
+ field public static final int endY = 16844052; // 0x1010514
field public static final deprecated int endYear = 16843133; // 0x101017d
field public static final int enterFadeDuration = 16843532; // 0x101030c
field public static final int entries = 16842930; // 0x10100b2
@@ -630,7 +634,7 @@
field public static final int expandableListViewStyle = 16842863; // 0x101006f
field public static final int expandableListViewWhiteStyle = 16843446; // 0x10102b6
field public static final int exported = 16842768; // 0x1010010
- field public static final int externalService = 16844048; // 0x1010510
+ field public static final int externalService = 16844047; // 0x101050f
field public static final int extraTension = 16843371; // 0x101026b
field public static final int extractNativeLibs = 16844010; // 0x10104ea
field public static final int factor = 16843219; // 0x10101d3
@@ -655,7 +659,7 @@
field public static final int fillBefore = 16843196; // 0x10101bc
field public static final int fillColor = 16843780; // 0x1010404
field public static final int fillEnabled = 16843343; // 0x101024f
- field public static final int fillType = 16844065; // 0x1010521
+ field public static final int fillType = 16844064; // 0x1010520
field public static final int fillViewport = 16843130; // 0x101017a
field public static final int filter = 16843035; // 0x101011b
field public static final int filterTouchesWhenObscured = 16843460; // 0x10102c4
@@ -671,6 +675,7 @@
field public static final int fontFamily = 16843692; // 0x10103ac
field public static final int fontFeatureSettings = 16843959; // 0x10104b7
field public static final int footerDividersEnabled = 16843311; // 0x101022f
+ field public static final int forceHasOverlappingRendering = 16844068; // 0x1010524
field public static final int foreground = 16843017; // 0x1010109
field public static final int foregroundGravity = 16843264; // 0x1010200
field public static final int foregroundTint = 16843885; // 0x101046d
@@ -747,8 +752,8 @@
field public static final int horizontalScrollViewStyle = 16843603; // 0x1010353
field public static final int horizontalSpacing = 16843028; // 0x1010114
field public static final int host = 16842792; // 0x1010028
- field public static final int hotSpotX = 16844057; // 0x1010519
- field public static final int hotSpotY = 16844058; // 0x101051a
+ field public static final int hotSpotX = 16844056; // 0x1010518
+ field public static final int hotSpotY = 16844057; // 0x1010519
field public static final int hyphenationFrequency = 16843998; // 0x10104de
field public static final int icon = 16842754; // 0x1010002
field public static final int iconPreview = 16843337; // 0x1010249
@@ -835,7 +840,7 @@
field public static final int label = 16842753; // 0x1010001
field public static final int labelFor = 16843718; // 0x10103c6
field public static final int labelTextSize = 16843317; // 0x1010235
- field public static final int languageTag = 16844042; // 0x101050a
+ field public static final int languageTag = 16844041; // 0x1010509
field public static final int largeHeap = 16843610; // 0x101035a
field public static final int largeScreens = 16843398; // 0x1010286
field public static final int largestWidthLimitDp = 16843622; // 0x1010366
@@ -893,7 +898,7 @@
field public static final int layout_y = 16843136; // 0x1010180
field public static final int left = 16843181; // 0x10101ad
field public static final int letterSpacing = 16843958; // 0x10104b6
- field public static final int level = 16844034; // 0x1010502
+ field public static final int level = 16844033; // 0x1010501
field public static final int lineSpacingExtra = 16843287; // 0x1010217
field public static final int lineSpacingMultiplier = 16843288; // 0x1010218
field public static final int lines = 16843092; // 0x1010154
@@ -926,7 +931,7 @@
field public static final int marqueeRepeatLimit = 16843293; // 0x101021d
field public static final int matchOrder = 16843855; // 0x101044f
field public static final int max = 16843062; // 0x1010136
- field public static final int maxButtonHeight = 16844031; // 0x10104ff
+ field public static final int maxButtonHeight = 16844030; // 0x10104fe
field public static final int maxDate = 16843584; // 0x1010340
field public static final int maxEms = 16843095; // 0x1010157
field public static final int maxHeight = 16843040; // 0x1010120
@@ -954,7 +959,7 @@
field public static final int minResizeWidth = 16843669; // 0x1010395
field public static final int minSdkVersion = 16843276; // 0x101020c
field public static final int minWidth = 16843071; // 0x101013f
- field public static final int minimalHeight = 16844023; // 0x10104f7
+ field public static final int minimalHeight = 16844067; // 0x1010523
field public static final int minimalWidth = 16844022; // 0x10104f6
field public static final int minimumHorizontalAngle = 16843901; // 0x101047d
field public static final int minimumVerticalAngle = 16843902; // 0x101047e
@@ -976,7 +981,7 @@
field public static final int nextFocusLeft = 16842977; // 0x10100e1
field public static final int nextFocusRight = 16842978; // 0x10100e2
field public static final int nextFocusUp = 16842979; // 0x10100e3
- field public static final int nfcAntennaPositionDrawable = 16844064; // 0x1010520
+ field public static final int nfcAntennaPositionDrawable = 16844063; // 0x101051f
field public static final int noHistory = 16843309; // 0x101022d
field public static final int normalScreens = 16843397; // 0x1010285
field public static final int notificationTimeout = 16843651; // 0x1010383
@@ -988,7 +993,7 @@
field public static final int numbersTextColor = 16843937; // 0x10104a1
field public static final deprecated int numeric = 16843109; // 0x1010165
field public static final int numericShortcut = 16843236; // 0x10101e4
- field public static final int offset = 16844054; // 0x1010516
+ field public static final int offset = 16844053; // 0x1010515
field public static final int onClick = 16843375; // 0x101026f
field public static final int oneshot = 16843159; // 0x1010197
field public static final int opacity = 16843550; // 0x101031e
@@ -1035,13 +1040,13 @@
field public static final deprecated int phoneNumber = 16843111; // 0x1010167
field public static final int pivotX = 16843189; // 0x10101b5
field public static final int pivotY = 16843190; // 0x10101b6
- field public static final int pointerShape = 16844043; // 0x101050b
+ field public static final int pointerShape = 16844042; // 0x101050a
field public static final int popupAnimationStyle = 16843465; // 0x10102c9
field public static final int popupBackground = 16843126; // 0x1010176
field public static final int popupCharacters = 16843332; // 0x1010244
field public static final int popupElevation = 16843916; // 0x101048c
- field public static final int popupEnterTransition = 16844066; // 0x1010522
- field public static final int popupExitTransition = 16844067; // 0x1010523
+ field public static final int popupEnterTransition = 16844065; // 0x1010521
+ field public static final int popupExitTransition = 16844066; // 0x1010522
field public static final int popupKeyboard = 16843331; // 0x1010243
field public static final int popupLayout = 16843323; // 0x101023b
field public static final int popupMenuStyle = 16843520; // 0x1010300
@@ -1050,7 +1055,7 @@
field public static final int port = 16842793; // 0x1010029
field public static final int positiveButtonText = 16843253; // 0x10101f5
field public static final int preferenceCategoryStyle = 16842892; // 0x101008c
- field public static final int preferenceFragmentStyle = 16844040; // 0x1010508
+ field public static final int preferenceFragmentStyle = 16844039; // 0x1010507
field public static final int preferenceInformationStyle = 16842893; // 0x101008d
field public static final int preferenceLayoutChild = 16842900; // 0x1010094
field public static final int preferenceScreenStyle = 16842891; // 0x101008b
@@ -1118,7 +1123,7 @@
field public static final int resizeClip = 16843983; // 0x10104cf
field public static final int resizeMode = 16843619; // 0x1010363
field public static final int resizeable = 16843405; // 0x101028d
- field public static final int resizeableActivity = 16844024; // 0x10104f8
+ field public static final int resizeableActivity = 16844023; // 0x10104f7
field public static final int resource = 16842789; // 0x1010025
field public static final int restoreAnyVersion = 16843450; // 0x10102ba
field public static final deprecated int restoreNeedsApplication = 16843421; // 0x101029d
@@ -1242,8 +1247,8 @@
field public static final int startColor = 16843165; // 0x101019d
field public static final int startDelay = 16843746; // 0x10103e2
field public static final int startOffset = 16843198; // 0x10101be
- field public static final int startX = 16844050; // 0x1010512
- field public static final int startY = 16844051; // 0x1010513
+ field public static final int startX = 16844049; // 0x1010511
+ field public static final int startY = 16844050; // 0x1010512
field public static final deprecated int startYear = 16843132; // 0x101017c
field public static final int stateListAnimator = 16843848; // 0x1010448
field public static final int stateNotNeeded = 16842774; // 0x1010016
@@ -1300,8 +1305,8 @@
field public static final int summaryOn = 16843247; // 0x10101ef
field public static final int supportsAssist = 16844016; // 0x10104f0
field public static final int supportsLaunchVoiceAssistFromKeyguard = 16844017; // 0x10104f1
- field public static final int supportsLocalInteraction = 16844049; // 0x1010511
- field public static final int supportsPictureInPicture = 16844025; // 0x10104f9
+ field public static final int supportsLocalInteraction = 16844048; // 0x1010510
+ field public static final int supportsPictureInPicture = 16844024; // 0x10104f8
field public static final int supportsRtl = 16843695; // 0x10103af
field public static final int supportsSwitchingToNextInputMethod = 16843755; // 0x10103eb
field public static final int supportsUploading = 16843419; // 0x101029b
@@ -1350,7 +1355,7 @@
field public static final int textAppearanceListItemSmall = 16843679; // 0x101039f
field public static final int textAppearanceMedium = 16842817; // 0x1010041
field public static final int textAppearanceMediumInverse = 16842820; // 0x1010044
- field public static final int textAppearancePopupMenuHeader = 16844036; // 0x1010504
+ field public static final int textAppearancePopupMenuHeader = 16844035; // 0x1010503
field public static final int textAppearanceSearchResultSubtitle = 16843424; // 0x10102a0
field public static final int textAppearanceSearchResultTitle = 16843425; // 0x10102a1
field public static final int textAppearanceSmall = 16842818; // 0x1010042
@@ -1408,9 +1413,9 @@
field public static final int thumbTint = 16843889; // 0x1010471
field public static final int thumbTintMode = 16843890; // 0x1010472
field public static final int thumbnail = 16843429; // 0x10102a5
- field public static final int tickMark = 16844044; // 0x101050c
- field public static final int tickMarkTint = 16844045; // 0x101050d
- field public static final int tickMarkTintMode = 16844046; // 0x101050e
+ field public static final int tickMark = 16844043; // 0x101050b
+ field public static final int tickMarkTint = 16844044; // 0x101050c
+ field public static final int tickMarkTintMode = 16844045; // 0x101050d
field public static final int tileMode = 16843265; // 0x1010201
field public static final int tileModeX = 16843895; // 0x1010477
field public static final int tileModeY = 16843896; // 0x1010478
@@ -1422,11 +1427,11 @@
field public static final int tintMode = 16843771; // 0x10103fb
field public static final int title = 16843233; // 0x10101e1
field public static final int titleCondensed = 16843234; // 0x10101e2
- field public static final int titleMargin = 16844026; // 0x10104fa
- field public static final int titleMarginBottom = 16844030; // 0x10104fe
- field public static final int titleMarginEnd = 16844028; // 0x10104fc
- field public static final int titleMarginStart = 16844027; // 0x10104fb
- field public static final int titleMarginTop = 16844029; // 0x10104fd
+ field public static final int titleMargin = 16844025; // 0x10104f9
+ field public static final int titleMarginBottom = 16844029; // 0x10104fd
+ field public static final int titleMarginEnd = 16844027; // 0x10104fb
+ field public static final int titleMarginStart = 16844026; // 0x10104fa
+ field public static final int titleMarginTop = 16844028; // 0x10104fc
field public static final int titleTextAppearance = 16843822; // 0x101042e
field public static final int titleTextColor = 16844003; // 0x10104e3
field public static final int titleTextStyle = 16843512; // 0x10102f8
@@ -1465,7 +1470,7 @@
field public static final int trimPathEnd = 16843785; // 0x1010409
field public static final int trimPathOffset = 16843786; // 0x101040a
field public static final int trimPathStart = 16843784; // 0x1010408
- field public static final int tunerCount = 16844063; // 0x101051f
+ field public static final int tunerCount = 16844062; // 0x101051e
field public static final int type = 16843169; // 0x10101a1
field public static final int typeface = 16842902; // 0x1010096
field public static final int uiOptions = 16843672; // 0x1010398
@@ -1473,7 +1478,7 @@
field public static final deprecated int unfocusedMonthDateColor = 16843588; // 0x1010344
field public static final int unselectedAlpha = 16843278; // 0x101020e
field public static final int updatePeriodMillis = 16843344; // 0x1010250
- field public static final int use32bitAbi = 16844055; // 0x1010517
+ field public static final int use32bitAbi = 16844054; // 0x1010516
field public static final int useDefaultMargins = 16843641; // 0x1010379
field public static final int useIntrinsicSizeAsMinimum = 16843536; // 0x1010310
field public static final int useLevel = 16843167; // 0x101019f
@@ -1485,7 +1490,7 @@
field public static final int valueType = 16843488; // 0x10102e0
field public static final int variablePadding = 16843157; // 0x1010195
field public static final int vendor = 16843751; // 0x10103e7
- field public static final int version = 16844059; // 0x101051b
+ field public static final int version = 16844058; // 0x101051a
field public static final int versionCode = 16843291; // 0x101021b
field public static final int versionName = 16843292; // 0x101021c
field public static final int verticalCorrection = 16843322; // 0x101023a
@@ -1529,7 +1534,7 @@
field public static final int windowAllowReturnTransitionOverlap = 16843835; // 0x101043b
field public static final int windowAnimationStyle = 16842926; // 0x10100ae
field public static final int windowBackground = 16842836; // 0x1010054
- field public static final int windowBackgroundFallback = 16844037; // 0x1010505
+ field public static final int windowBackgroundFallback = 16844036; // 0x1010504
field public static final int windowClipToOutline = 16843947; // 0x10104ab
field public static final int windowCloseOnTouchOutside = 16843611; // 0x101035b
field public static final int windowContentOverlay = 16842841; // 0x1010059
@@ -2583,6 +2588,7 @@
field public static final int Widget_Material_CompoundButton_CheckBox = 16974435; // 0x1030263
field public static final int Widget_Material_CompoundButton_RadioButton = 16974436; // 0x1030264
field public static final int Widget_Material_CompoundButton_Star = 16974437; // 0x1030265
+ field public static final int Widget_Material_CompoundButton_Switch = 16974554; // 0x10302da
field public static final int Widget_Material_DatePicker = 16974438; // 0x1030266
field public static final int Widget_Material_DropDownItem = 16974439; // 0x1030267
field public static final int Widget_Material_DropDownItem_Spinner = 16974440; // 0x1030268
@@ -2617,6 +2623,7 @@
field public static final int Widget_Material_Light_CompoundButton_CheckBox = 16974500; // 0x10302a4
field public static final int Widget_Material_Light_CompoundButton_RadioButton = 16974501; // 0x10302a5
field public static final int Widget_Material_Light_CompoundButton_Star = 16974502; // 0x10302a6
+ field public static final int Widget_Material_Light_CompoundButton_Switch = 16974555; // 0x10302db
field public static final int Widget_Material_Light_DatePicker = 16974503; // 0x10302a7
field public static final int Widget_Material_Light_DropDownItem = 16974504; // 0x10302a8
field public static final int Widget_Material_Light_DropDownItem_Spinner = 16974505; // 0x10302a9
@@ -3537,7 +3544,7 @@
method public boolean dispatchTouchEvent(android.view.MotionEvent);
method public boolean dispatchTrackballEvent(android.view.MotionEvent);
method public void dump(java.lang.String, java.io.FileDescriptor, java.io.PrintWriter, java.lang.String[]);
- method public void enterPictureInPicture();
+ method public void enterPictureInPictureMode();
method public android.view.View findViewById(int);
method public void finish();
method public void finishActivity(int);
@@ -3577,8 +3584,6 @@
method public android.view.Window getWindow();
method public android.view.WindowManager getWindowManager();
method public boolean hasWindowFocus();
- method public boolean inMultiWindow();
- method public boolean inPictureInPicture();
method public void invalidateOptionsMenu();
method public boolean isBackgroundVisibleBehind();
method public boolean isChangingConfigurations();
@@ -3586,7 +3591,10 @@
method public boolean isDestroyed();
method public boolean isFinishing();
method public boolean isImmersive();
+ method public boolean isInMultiWindowMode();
+ method public boolean isInPictureInPictureMode();
method public boolean isLocalVoiceInteractionSupported();
+ method public boolean isOverlayWithDecorCaptionEnabled();
method public boolean isTaskRoot();
method public boolean isVoiceInteraction();
method public boolean isVoiceInteractionRoot();
@@ -3634,7 +3642,7 @@
method public void onLowMemory();
method public boolean onMenuItemSelected(int, android.view.MenuItem);
method public boolean onMenuOpened(int, android.view.Menu);
- method public void onMultiWindowChanged(boolean);
+ method public void onMultiWindowModeChanged(boolean);
method public boolean onNavigateUp();
method public boolean onNavigateUpFromChild(android.app.Activity);
method protected void onNewIntent(android.content.Intent);
@@ -3642,7 +3650,7 @@
method public void onOptionsMenuClosed(android.view.Menu);
method public void onPanelClosed(int, android.view.Menu);
method protected void onPause();
- method public void onPictureInPictureChanged(boolean);
+ method public void onPictureInPictureModeChanged(boolean);
method protected void onPostCreate(android.os.Bundle);
method public void onPostCreate(android.os.Bundle, android.os.PersistableBundle);
method protected void onPostResume();
@@ -3680,7 +3688,6 @@
method public android.view.ActionMode onWindowStartingActionMode(android.view.ActionMode.Callback, int);
method public void openContextMenu(android.view.View);
method public void openOptionsMenu();
- method public void overlayWithDecorCaption(boolean);
method public void overridePendingTransition(int, int);
method public void postponeEnterTransition();
method public void recreate();
@@ -3709,6 +3716,7 @@
method public void setImmersive(boolean);
method public void setIntent(android.content.Intent);
method public final void setMediaController(android.media.session.MediaController);
+ method public void setOverlayWithDecorCaptionEnabled(boolean);
method public final deprecated void setProgress(int);
method public final deprecated void setProgressBarIndeterminate(boolean);
method public final deprecated void setProgressBarIndeterminateVisibility(boolean);
@@ -4566,11 +4574,11 @@
method public void onInflate(android.content.Context, android.util.AttributeSet, android.os.Bundle);
method public deprecated void onInflate(android.app.Activity, android.util.AttributeSet, android.os.Bundle);
method public void onLowMemory();
- method public void onMultiWindowChanged(boolean);
+ method public void onMultiWindowModeChanged(boolean);
method public boolean onOptionsItemSelected(android.view.MenuItem);
method public void onOptionsMenuClosed(android.view.Menu);
method public void onPause();
- method public void onPictureInPictureChanged(boolean);
+ method public void onPictureInPictureModeChanged(boolean);
method public void onPrepareOptionsMenu(android.view.Menu);
method public void onRequestPermissionsResult(int, java.lang.String[], int[]);
method public void onResume();
@@ -4651,11 +4659,11 @@
method public void dispatchDestroy();
method public void dispatchDestroyView();
method public void dispatchLowMemory();
- method public void dispatchMultiWindowChanged(boolean);
+ method public void dispatchMultiWindowModeChanged(boolean);
method public boolean dispatchOptionsItemSelected(android.view.MenuItem);
method public void dispatchOptionsMenuClosed(android.view.Menu);
method public void dispatchPause();
- method public void dispatchPictureInPictureChanged(boolean);
+ method public void dispatchPictureInPictureModeChanged(boolean);
method public boolean dispatchPrepareOptionsMenu(android.view.Menu);
method public void dispatchResume();
method public void dispatchStart();
@@ -5888,8 +5896,8 @@
field public static final java.lang.String COMMAND_SECONDARY_TAP = "android.wallpaper.secondaryTap";
field public static final java.lang.String COMMAND_TAP = "android.wallpaper.tap";
field public static final java.lang.String EXTRA_LIVE_WALLPAPER_COMPONENT = "android.service.wallpaper.extra.LIVE_WALLPAPER_COMPONENT";
- field public static final int FLAG_SET_LOCK = 2; // 0x2
- field public static final int FLAG_SET_SYSTEM = 1; // 0x1
+ field public static final int FLAG_LOCK = 2; // 0x2
+ field public static final int FLAG_SYSTEM = 1; // 0x1
field public static final java.lang.String WALLPAPER_PREVIEW_META_DATA = "android.wallpaper.preview";
}
@@ -5992,7 +6000,7 @@
method public deprecated java.lang.String getDeviceInitializerApp();
method public deprecated android.content.ComponentName getDeviceInitializerComponent();
method public java.lang.String getDeviceOwner();
- method public java.lang.String getDeviceOwnerLockScreenInfo();
+ method public java.lang.CharSequence getDeviceOwnerLockScreenInfo();
method public java.lang.String getDeviceOwnerNameOnAnyUser();
method public java.util.List<byte[]> getInstalledCaCerts(android.content.ComponentName);
method public int getKeyguardDisabledFeatures(android.content.ComponentName);
@@ -6001,7 +6009,6 @@
method public long getMaximumTimeToLock(android.content.ComponentName);
method public int getOrganizationColor(android.content.ComponentName);
method public java.lang.String getOrganizationName(android.content.ComponentName);
- method public boolean getPackageSuspended(android.content.ComponentName, java.lang.String);
method public android.app.admin.DevicePolicyManager getParentProfileInstance(android.content.ComponentName);
method public long getPasswordExpiration(android.content.ComponentName);
method public long getPasswordExpirationTimeout(android.content.ComponentName);
@@ -6036,14 +6043,16 @@
method public boolean hasGrantedPolicy(android.content.ComponentName, int);
method public boolean installCaCert(android.content.ComponentName, byte[]);
method public boolean installKeyPair(android.content.ComponentName, java.security.PrivateKey, java.security.cert.Certificate, java.lang.String);
- method public boolean installKeyPair(android.content.ComponentName, java.security.PrivateKey, java.security.cert.Certificate, java.lang.String, boolean);
+ method public boolean installKeyPair(android.content.ComponentName, java.security.PrivateKey, java.security.cert.Certificate[], java.lang.String, boolean);
method public boolean isActivePasswordSufficient();
method public boolean isAdminActive(android.content.ComponentName);
method public boolean isApplicationHidden(android.content.ComponentName, java.lang.String);
method public boolean isCallerApplicationRestrictionsManagingPackage();
method public boolean isDeviceOwnerApp(java.lang.String);
method public boolean isLockTaskPermitted(java.lang.String);
+ method public boolean isManagedProfile(android.content.ComponentName);
method public boolean isMasterVolumeMuted(android.content.ComponentName);
+ method public boolean isPackageSuspended(android.content.ComponentName, java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
method public boolean isProfileOwnerApp(java.lang.String);
method public boolean isProvisioningAllowed(java.lang.String);
method public boolean isSecurityLoggingEnabled(android.content.ComponentName);
@@ -6071,7 +6080,7 @@
method public void setCertInstallerPackage(android.content.ComponentName, java.lang.String) throws java.lang.SecurityException;
method public void setCrossProfileCallerIdDisabled(android.content.ComponentName, boolean);
method public void setCrossProfileContactsSearchDisabled(android.content.ComponentName, boolean);
- method public boolean setDeviceOwnerLockScreenInfo(android.content.ComponentName, java.lang.String);
+ method public void setDeviceOwnerLockScreenInfo(android.content.ComponentName, java.lang.CharSequence);
method public void setGlobalSetting(android.content.ComponentName, java.lang.String, java.lang.String);
method public boolean setKeyguardDisabled(android.content.ComponentName, boolean);
method public void setKeyguardDisabledFeatures(android.content.ComponentName, int);
@@ -8531,8 +8540,6 @@
method public java.lang.String getPackageResourcePath();
method public android.content.res.Resources getResources();
method public android.content.SharedPreferences getSharedPreferences(java.lang.String, int);
- method public android.content.SharedPreferences getSharedPreferences(java.io.File, int);
- method public java.io.File getSharedPreferencesPath(java.lang.String);
method public java.lang.Object getSystemService(java.lang.String);
method public java.lang.String getSystemServiceName(java.lang.Class<?>);
method public android.content.res.Resources.Theme getTheme();
@@ -8832,8 +8839,9 @@
field public static final java.lang.String ACTION_LOCKED_BOOT_COMPLETED = "android.intent.action.LOCKED_BOOT_COMPLETED";
field public static final java.lang.String ACTION_MAIN = "android.intent.action.MAIN";
field public static final java.lang.String ACTION_MANAGED_PROFILE_ADDED = "android.intent.action.MANAGED_PROFILE_ADDED";
- field public static final java.lang.String ACTION_MANAGED_PROFILE_AVAILABILITY_CHANGED = "android.intent.action.MANAGED_PROFILE_AVAILABILITY_CHANGED";
+ field public static final java.lang.String ACTION_MANAGED_PROFILE_AVAILABLE = "android.intent.action.MANAGED_PROFILE_AVAILABLE";
field public static final java.lang.String ACTION_MANAGED_PROFILE_REMOVED = "android.intent.action.MANAGED_PROFILE_REMOVED";
+ field public static final java.lang.String ACTION_MANAGED_PROFILE_UNAVAILABLE = "android.intent.action.MANAGED_PROFILE_UNAVAILABLE";
field public static final java.lang.String ACTION_MANAGED_PROFILE_UNLOCKED = "android.intent.action.MANAGED_PROFILE_UNLOCKED";
field public static final java.lang.String ACTION_MANAGE_NETWORK_USAGE = "android.intent.action.MANAGE_NETWORK_USAGE";
field public static final java.lang.String ACTION_MANAGE_PACKAGE_STORAGE = "android.intent.action.MANAGE_PACKAGE_STORAGE";
@@ -10311,6 +10319,7 @@
field public static final int PROTECTION_FLAG_PRE23 = 128; // 0x80
field public static final int PROTECTION_FLAG_PREINSTALLED = 1024; // 0x400
field public static final int PROTECTION_FLAG_PRIVILEGED = 16; // 0x10
+ field public static final int PROTECTION_FLAG_SETUP = 2048; // 0x800
field public static final deprecated int PROTECTION_FLAG_SYSTEM = 16; // 0x10
field public static final int PROTECTION_FLAG_VERIFIER = 512; // 0x200
field public static final int PROTECTION_MASK_BASE = 15; // 0xf
@@ -10388,7 +10397,7 @@
field public java.lang.String permission;
}
- public class ShortcutInfo implements android.os.Parcelable {
+ public final class ShortcutInfo implements android.os.Parcelable {
method public int describeContents();
method public android.content.ComponentName getActivityComponent();
method public android.os.PersistableBundle getExtras();
@@ -10396,6 +10405,7 @@
method public android.content.Intent getIntent();
method public long getLastChangedTimestamp();
method public java.lang.String getPackageName();
+ method public java.lang.String getText();
method public java.lang.String getTitle();
method public int getWeight();
method public boolean hasIconFile();
@@ -10423,6 +10433,7 @@
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 android.content.pm.ShortcutInfo.Builder setIntent(android.content.Intent);
+ method public android.content.pm.ShortcutInfo.Builder setText(java.lang.String);
method public android.content.pm.ShortcutInfo.Builder setTitle(java.lang.String);
method public android.content.pm.ShortcutInfo.Builder setWeight(int);
}
@@ -13897,6 +13908,7 @@
public final class Sensor {
method public int getFifoMaxEventCount();
method public int getFifoReservedEventCount();
+ method public int getId();
method public int getMaxDelay();
method public float getMaximumRange();
method public int getMinDelay();
@@ -13909,7 +13921,9 @@
method public java.util.UUID getUuid();
method public java.lang.String getVendor();
method public int getVersion();
+ method public boolean isAdditionalInfoSupported();
method public boolean isDataInjectionSupported();
+ method public boolean isDynamicSensor();
method public boolean isWakeUpSensor();
field public static final int REPORTING_MODE_CONTINUOUS = 0; // 0x0
field public static final int REPORTING_MODE_ONE_SHOT = 2; // 0x2
@@ -14034,8 +14048,9 @@
method public deprecated int getSensors();
method public boolean initDataInjection(boolean);
method public boolean injectSensorData(android.hardware.Sensor, float[], int, long);
- method public void registerDynamicSensorCallback(android.hardware.SensorManager.DynamicSensorConnectionCallback);
- method public void registerDynamicSensorCallback(android.hardware.SensorManager.DynamicSensorConnectionCallback, android.os.Handler);
+ method public boolean isDynamicSensorDiscoverySupported();
+ method public void registerDynamicSensorCallback(android.hardware.SensorManager.DynamicSensorCallback);
+ method public void registerDynamicSensorCallback(android.hardware.SensorManager.DynamicSensorCallback, android.os.Handler);
method public deprecated boolean registerListener(android.hardware.SensorListener, int);
method public deprecated boolean registerListener(android.hardware.SensorListener, int, int);
method public boolean registerListener(android.hardware.SensorEventListener, android.hardware.Sensor, int);
@@ -14044,7 +14059,7 @@
method public boolean registerListener(android.hardware.SensorEventListener, android.hardware.Sensor, int, int, android.os.Handler);
method public static boolean remapCoordinateSystem(float[], int, int, float[]);
method public boolean requestTriggerSensor(android.hardware.TriggerEventListener, android.hardware.Sensor);
- method public void unregisterDynamicSensorCallback(android.hardware.SensorManager.DynamicSensorConnectionCallback);
+ method public void unregisterDynamicSensorCallback(android.hardware.SensorManager.DynamicSensorCallback);
method public deprecated void unregisterListener(android.hardware.SensorListener);
method public deprecated void unregisterListener(android.hardware.SensorListener, int);
method public void unregisterListener(android.hardware.SensorEventListener, android.hardware.Sensor);
@@ -14109,8 +14124,8 @@
field public static final float STANDARD_GRAVITY = 9.80665f;
}
- public static abstract class SensorManager.DynamicSensorConnectionCallback {
- ctor public SensorManager.DynamicSensorConnectionCallback();
+ public static abstract class SensorManager.DynamicSensorCallback {
+ ctor public SensorManager.DynamicSensorCallback();
method public void onDynamicSensorConnected(android.hardware.Sensor);
method public void onDynamicSensorDisconnected(android.hardware.Sensor);
}
@@ -15259,6 +15274,7 @@
ctor public ContextHubInfo();
method public int describeContents();
method public int getId();
+ method public int getMaxPacketLengthBytes();
method public android.hardware.location.MemoryRegion[] getMemoryRegions();
method public java.lang.String getName();
method public float getPeakMips();
@@ -15286,10 +15302,6 @@
method public int sendMessage(int, int, android.hardware.location.ContextHubMessage);
method public int unloadNanoApp(int);
method public int unregisterCallback(android.hardware.location.ContextHubManager.Callback);
- field public static final int ANY_HUB = -1; // 0xffffffff
- field public static final int MSG_DATA_SEND = 3; // 0x3
- field public static final int MSG_LOAD_NANO_APP = 1; // 0x1
- field public static final int MSG_UNLOAD_NANO_APP = 2; // 0x2
}
public static abstract class ContextHubManager.Callback {
@@ -15483,7 +15495,7 @@
public class NanoAppInstanceInfo {
ctor public NanoAppInstanceInfo();
method public int describeContents();
- method public int getAppId();
+ method public long getAppId();
method public int getAppVersion();
method public int getContexthubId();
method public int getHandle();
@@ -15494,17 +15506,6 @@
method public int getNeededWriteMemBytes();
method public int[] getOutputEvents();
method public java.lang.String getPublisher();
- method public void setAppId(int);
- method public void setAppVersion(int);
- method public void setContexthubId(int);
- method public void setHandle(int);
- method public void setName(java.lang.String);
- method public void setNeededExecMemBytes(int);
- method public void setNeededReadMemBytes(int);
- method public void setNeededSensors(int[]);
- method public void setNeededWriteMemBytes(int);
- method public void setOutputEvents(int[]);
- method public void setPublisher(java.lang.String);
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.hardware.location.NanoAppInstanceInfo> CREATOR;
}
@@ -16002,7 +16003,6 @@
public static abstract interface UCharacter.BidiPairedBracketType {
field public static final int CLOSE = 2; // 0x2
- field public static final int COUNT = 3; // 0x3
field public static final int NONE = 0; // 0x0
field public static final int OPEN = 1; // 0x1
}
@@ -16011,7 +16011,6 @@
field public static final int CANONICAL = 1; // 0x1
field public static final int CIRCLE = 3; // 0x3
field public static final int COMPAT = 2; // 0x2
- field public static final int COUNT = 18; // 0x12
field public static final int FINAL = 4; // 0x4
field public static final int FONT = 5; // 0x5
field public static final int FRACTION = 6; // 0x6
@@ -16031,7 +16030,6 @@
public static abstract interface UCharacter.EastAsianWidth {
field public static final int AMBIGUOUS = 1; // 0x1
- field public static final int COUNT = 6; // 0x6
field public static final int FULLWIDTH = 3; // 0x3
field public static final int HALFWIDTH = 2; // 0x2
field public static final int NARROW = 4; // 0x4
@@ -16041,7 +16039,6 @@
public static abstract interface UCharacter.GraphemeClusterBreak {
field public static final int CONTROL = 1; // 0x1
- field public static final int COUNT = 13; // 0xd
field public static final int CR = 2; // 0x2
field public static final int EXTEND = 3; // 0x3
field public static final int L = 4; // 0x4
@@ -16057,7 +16054,6 @@
}
public static abstract interface UCharacter.HangulSyllableType {
- field public static final int COUNT = 6; // 0x6
field public static final int LEADING_JAMO = 1; // 0x1
field public static final int LVT_SYLLABLE = 5; // 0x5
field public static final int LV_SYLLABLE = 4; // 0x4
@@ -16073,7 +16069,6 @@
field public static final int BEH = 4; // 0x4
field public static final int BETH = 5; // 0x5
field public static final int BURUSHASKI_YEH_BARREE = 54; // 0x36
- field public static final int COUNT = 86; // 0x56
field public static final int DAL = 6; // 0x6
field public static final int DALATH_RISH = 7; // 0x7
field public static final int E = 8; // 0x8
@@ -16158,7 +16153,6 @@
}
public static abstract interface UCharacter.JoiningType {
- field public static final int COUNT = 6; // 0x6
field public static final int DUAL_JOINING = 2; // 0x2
field public static final int JOIN_CAUSING = 1; // 0x1
field public static final int LEFT_JOINING = 3; // 0x3
@@ -16181,7 +16175,6 @@
field public static final int COMPLEX_CONTEXT = 24; // 0x18
field public static final int CONDITIONAL_JAPANESE_STARTER = 37; // 0x25
field public static final int CONTINGENT_BREAK = 7; // 0x7
- field public static final int COUNT = 40; // 0x28
field public static final int EXCLAMATION = 11; // 0xb
field public static final int GLUE = 12; // 0xc
field public static final int H2 = 31; // 0x1f
@@ -16213,7 +16206,6 @@
}
public static abstract interface UCharacter.NumericType {
- field public static final int COUNT = 4; // 0x4
field public static final int DECIMAL = 1; // 0x1
field public static final int DIGIT = 2; // 0x2
field public static final int NONE = 0; // 0x0
@@ -16223,7 +16215,6 @@
public static abstract interface UCharacter.SentenceBreak {
field public static final int ATERM = 1; // 0x1
field public static final int CLOSE = 2; // 0x2
- field public static final int COUNT = 15; // 0xf
field public static final int CR = 11; // 0xb
field public static final int EXTEND = 12; // 0xc
field public static final int FORMAT = 3; // 0x3
@@ -16366,7 +16357,6 @@
field public static final android.icu.lang.UCharacter.UnicodeBlock COPTIC_EPACT_NUMBERS;
field public static final int COPTIC_EPACT_NUMBERS_ID = 223; // 0xdf
field public static final int COPTIC_ID = 132; // 0x84
- field public static final int COUNT = 263; // 0x107
field public static final android.icu.lang.UCharacter.UnicodeBlock COUNTING_ROD_NUMERALS;
field public static final int COUNTING_ROD_NUMERALS_ID = 154; // 0x9a
field public static final android.icu.lang.UCharacter.UnicodeBlock CUNEIFORM;
@@ -16780,7 +16770,6 @@
public static abstract interface UCharacter.WordBreak {
field public static final int ALETTER = 1; // 0x1
- field public static final int COUNT = 17; // 0x11
field public static final int CR = 8; // 0x8
field public static final int DOUBLE_QUOTE = 16; // 0x10
field public static final int EXTEND = 9; // 0x9
@@ -16811,7 +16800,6 @@
}
public static abstract interface UCharacterEnums.ECharacterCategory {
- field public static final byte CHAR_CATEGORY_COUNT = 30; // 0x1e
field public static final byte COMBINING_SPACING_MARK = 8; // 0x8
field public static final byte CONNECTOR_PUNCTUATION = 22; // 0x16
field public static final byte CONTROL = 15; // 0xf
@@ -16851,7 +16839,6 @@
field public static final int ARABIC_NUMBER = 5; // 0x5
field public static final int BLOCK_SEPARATOR = 7; // 0x7
field public static final int BOUNDARY_NEUTRAL = 18; // 0x12
- field public static final int CHAR_DIRECTION_COUNT = 23; // 0x17
field public static final int COMMON_NUMBER_SEPARATOR = 6; // 0x6
field public static final byte DIRECTIONALITY_ARABIC_NUMBER = 5; // 0x5
field public static final byte DIRECTIONALITY_BOUNDARY_NEUTRAL = 18; // 0x12
@@ -16904,7 +16891,6 @@
field public static final int BIDI_MIRRORING_GLYPH = 16385; // 0x4001
field public static final int BIDI_PAIRED_BRACKET = 16397; // 0x400d
field public static final int BIDI_PAIRED_BRACKET_TYPE = 4117; // 0x1015
- field public static final int BINARY_LIMIT = 57; // 0x39
field public static final int BINARY_START = 0; // 0x0
field public static final int BLOCK = 4097; // 0x1001
field public static final int CANONICAL_COMBINING_CLASS = 4098; // 0x1002
@@ -16923,7 +16909,6 @@
field public static final int DEFAULT_IGNORABLE_CODE_POINT = 5; // 0x5
field public static final int DEPRECATED = 6; // 0x6
field public static final int DIACRITIC = 7; // 0x7
- field public static final int DOUBLE_LIMIT = 12289; // 0x3001
field public static final int DOUBLE_START = 12288; // 0x3000
field public static final int EAST_ASIAN_WIDTH = 4100; // 0x1004
field public static final int EXTENDER = 8; // 0x8
@@ -16942,7 +16927,6 @@
field public static final int IDS_TRINARY_OPERATOR = 19; // 0x13
field public static final int ID_CONTINUE = 15; // 0xf
field public static final int ID_START = 16; // 0x10
- field public static final int INT_LIMIT = 4118; // 0x1016
field public static final int INT_START = 4096; // 0x1000
field public static final int JOINING_GROUP = 4102; // 0x1006
field public static final int JOINING_TYPE = 4103; // 0x1007
@@ -16952,7 +16936,6 @@
field public static final int LOGICAL_ORDER_EXCEPTION = 21; // 0x15
field public static final int LOWERCASE = 22; // 0x16
field public static final int LOWERCASE_MAPPING = 16388; // 0x4004
- field public static final int MASK_LIMIT = 8193; // 0x2001
field public static final int MASK_START = 8192; // 0x2000
field public static final int MATH = 23; // 0x17
field public static final int NAME = 16389; // 0x4005
@@ -16967,7 +16950,6 @@
field public static final int NONCHARACTER_CODE_POINT = 24; // 0x18
field public static final int NUMERIC_TYPE = 4105; // 0x1009
field public static final int NUMERIC_VALUE = 12288; // 0x3000
- field public static final int OTHER_PROPERTY_LIMIT = 28673; // 0x7001
field public static final int OTHER_PROPERTY_START = 28672; // 0x7000
field public static final int PATTERN_SYNTAX = 42; // 0x2a
field public static final int PATTERN_WHITE_SPACE = 43; // 0x2b
@@ -16987,7 +16969,6 @@
field public static final int SIMPLE_TITLECASE_MAPPING = 16392; // 0x4008
field public static final int SIMPLE_UPPERCASE_MAPPING = 16393; // 0x4009
field public static final int SOFT_DOTTED = 27; // 0x1b
- field public static final int STRING_LIMIT = 16398; // 0x400e
field public static final int STRING_START = 16384; // 0x4000
field public static final int S_TERM = 35; // 0x23
field public static final int TERMINAL_PUNCTUATION = 28; // 0x1c
@@ -17004,7 +16985,6 @@
}
public static abstract interface UProperty.NameChoice {
- field public static final int COUNT = 2; // 0x2
field public static final int LONG = 1; // 0x1
field public static final int SHORT = 0; // 0x0
}
@@ -17049,7 +17029,6 @@
field public static final int CHAM = 66; // 0x42
field public static final int CHEROKEE = 6; // 0x6
field public static final int CIRTH = 67; // 0x43
- field public static final int CODE_LIMIT = 167; // 0xa7
field public static final int COMMON = 0; // 0x0
field public static final int COPTIC = 7; // 0x7
field public static final int CUNEIFORM = 101; // 0x65
@@ -17444,7 +17423,6 @@
public final class CollationKey implements java.lang.Comparable {
ctor public CollationKey(java.lang.String, byte[]);
- ctor public CollationKey(java.lang.String, android.icu.text.RawCollationKey);
method public int compareTo(android.icu.text.CollationKey);
method public boolean equals(android.icu.text.CollationKey);
method public android.icu.text.CollationKey getBound(int, int);
@@ -17454,7 +17432,6 @@
}
public static final class CollationKey.BoundMode {
- field public static final int COUNT = 3; // 0x3
field public static final int LOWER = 0; // 0x0
field public static final int UPPER = 1; // 0x1
field public static final int UPPER_LONG = 2; // 0x2
@@ -17486,7 +17463,6 @@
method public static final java.lang.String[] getKeywordValuesForLocale(java.lang.String, android.icu.util.ULocale, boolean);
method public static final java.lang.String[] getKeywords();
method public int getMaxVariable();
- method public abstract android.icu.text.RawCollationKey getRawCollationKey(java.lang.String, android.icu.text.RawCollationKey);
method public int[] getReorderCodes();
method public int getStrength();
method public android.icu.text.UnicodeSet getTailoredSet();
@@ -17526,7 +17502,6 @@
field public static final int DEFAULT = -1; // 0xffffffff
field public static final int DIGIT = 4100; // 0x1004
field public static final int FIRST = 4096; // 0x1000
- field public static final int LIMIT = 4101; // 0x1005
field public static final int NONE = 103; // 0x67
field public static final int OTHERS = 103; // 0x67
field public static final int PUNCTUATION = 4097; // 0x1001
@@ -17639,7 +17614,6 @@
field public static final int DOW_LOCAL_FIELD = 19; // 0x13
field public static final int ERA_FIELD = 0; // 0x0
field public static final int EXTENDED_YEAR_FIELD = 20; // 0x14
- field public static final int FIELD_COUNT = 36; // 0x24
field public static final int FRACTIONAL_SECOND_FIELD = 8; // 0x8
field public static final int FULL = 0; // 0x0
field public static final java.lang.String GENERIC_TZ = "vvvv";
@@ -17883,7 +17857,6 @@
field public static final int MONTH = 3; // 0x3
field public static final int QUARTER = 2; // 0x2
field public static final int SECOND = 13; // 0xd
- field public static final int TYPE_LIMIT = 16; // 0x10
field public static final int WEEKDAY = 6; // 0x6
field public static final int WEEK_OF_MONTH = 5; // 0x5
field public static final int WEEK_OF_YEAR = 4; // 0x4
@@ -18514,14 +18487,6 @@
enum_constant public static final android.icu.text.PluralRules.PluralType ORDINAL;
}
- public final class RawCollationKey extends android.icu.util.ByteArrayWrapper {
- ctor public RawCollationKey();
- ctor public RawCollationKey(int);
- ctor public RawCollationKey(byte[]);
- ctor public RawCollationKey(byte[], int);
- method public int compareTo(android.icu.text.RawCollationKey);
- }
-
public final class RelativeDateTimeFormatter {
method public java.lang.String combineDateAndTime(java.lang.String, java.lang.String);
method public java.lang.String format(double, android.icu.text.RelativeDateTimeFormatter.Direction, android.icu.text.RelativeDateTimeFormatter.RelativeUnit);
@@ -18605,7 +18570,6 @@
method public android.icu.text.CollationKey getCollationKey(java.lang.String);
method public void getContractionsAndExpansions(android.icu.text.UnicodeSet, android.icu.text.UnicodeSet, boolean) throws java.lang.Exception;
method public boolean getNumericCollation();
- method public android.icu.text.RawCollationKey getRawCollationKey(java.lang.String, android.icu.text.RawCollationKey);
method public java.lang.String getRules();
method public java.lang.String getRules(boolean);
method public android.icu.util.VersionInfo getUCAVersion();
@@ -19100,19 +19064,6 @@
field public static final int BE = 0; // 0x0
}
- public class ByteArrayWrapper implements java.lang.Comparable {
- ctor public ByteArrayWrapper();
- ctor public ByteArrayWrapper(byte[], int);
- ctor public ByteArrayWrapper(java.nio.ByteBuffer);
- method public final android.icu.util.ByteArrayWrapper append(byte[], int, int);
- method public int compareTo(android.icu.util.ByteArrayWrapper);
- method public android.icu.util.ByteArrayWrapper ensureCapacity(int);
- method public final byte[] releaseBytes();
- method public final android.icu.util.ByteArrayWrapper set(byte[], int, int);
- field public byte[] bytes;
- field public int size;
- }
-
abstract class CECalendar extends android.icu.util.Calendar {
ctor protected CECalendar();
ctor protected CECalendar(android.icu.util.TimeZone);
@@ -20425,10 +20376,19 @@
field public static final int MULTIPATH_INDICATOR_DETECTED = 1; // 0x1
field public static final int MULTIPATH_INDICATOR_NOT_USED = 2; // 0x2
field public static final int MULTIPATH_INDICATOR_UNKNOWN = 0; // 0x0
+ field public static final int STATE_BDS_D2_BIT_SYNC = 256; // 0x100
+ field public static final int STATE_BDS_D2_SUBFRAME_SYNC = 512; // 0x200
field public static final int STATE_BIT_SYNC = 2; // 0x2
field public static final int STATE_CODE_LOCK = 1; // 0x1
+ field public static final int STATE_GAL_E1BC_CODE_LOCK = 1024; // 0x400
+ field public static final int STATE_GAL_E1B_PAGE_SYNC = 4096; // 0x1000
+ field public static final int STATE_GAL_E1C_2ND_CODE_LOCK = 2048; // 0x800
+ field public static final int STATE_GLO_STRING_SYNC = 64; // 0x40
+ field public static final int STATE_GLO_TOD_DECODED = 128; // 0x80
field public static final int STATE_MSEC_AMBIGUOUS = 16; // 0x10
+ field public static final int STATE_SBAS_SYNC = 8192; // 0x2000
field public static final int STATE_SUBFRAME_SYNC = 4; // 0x4
+ field public static final int STATE_SYMBOL_SYNC = 32; // 0x20
field public static final int STATE_TOW_DECODED = 8; // 0x8
field public static final int STATE_UNKNOWN = 0; // 0x0
}
@@ -21331,7 +21291,7 @@
public static abstract class AudioManager.AudioRecordingCallback {
ctor public AudioManager.AudioRecordingCallback();
- method public void onRecordConfigChanged(android.media.AudioRecordingConfiguration[]);
+ method public void onRecordingConfigChanged(android.media.AudioRecordingConfiguration[]);
}
public static abstract interface AudioManager.OnAudioFocusChangeListener {
@@ -21611,6 +21571,7 @@
method public int getAttributeInt(java.lang.String, int);
method public boolean getLatLong(float[]);
method public byte[] getThumbnail();
+ method public long[] getThumbnailRange();
method public boolean hasThumbnail();
method public void saveAttributes() throws java.io.IOException;
method public void setAttribute(java.lang.String, java.lang.String);
@@ -21623,7 +21584,7 @@
field public static final int ORIENTATION_TRANSPOSE = 5; // 0x5
field public static final int ORIENTATION_TRANSVERSE = 7; // 0x7
field public static final int ORIENTATION_UNDEFINED = 0; // 0x0
- field public static final java.lang.String TAG_APERTURE = "FNumber";
+ field public static final deprecated java.lang.String TAG_APERTURE = "FNumber";
field public static final java.lang.String TAG_APERTURE_VALUE = "ApertureValue";
field public static final java.lang.String TAG_ARTIST = "Artist";
field public static final java.lang.String TAG_BITS_PER_SAMPLE = "BitsPerSample";
@@ -21694,7 +21655,7 @@
field public static final java.lang.String TAG_IMAGE_UNIQUE_ID = "ImageUniqueID";
field public static final java.lang.String TAG_IMAGE_WIDTH = "ImageWidth";
field public static final java.lang.String TAG_INTEROPERABILITY_INDEX = "InteroperabilityIndex";
- field public static final java.lang.String TAG_ISO = "ISOSpeedRatings";
+ field public static final deprecated java.lang.String TAG_ISO = "ISOSpeedRatings";
field public static final java.lang.String TAG_ISO_SPEED_RATINGS = "ISOSpeedRatings";
field public static final java.lang.String TAG_JPEG_INTERCHANGE_FORMAT = "JPEGInterchangeFormat";
field public static final java.lang.String TAG_JPEG_INTERCHANGE_FORMAT_LENGTH = "JPEGInterchangeFormatLength";
@@ -22102,12 +22063,13 @@
field public static final int DolbyVisionLevelUhd30 = 64; // 0x40
field public static final int DolbyVisionLevelUhd48 = 128; // 0x80
field public static final int DolbyVisionLevelUhd60 = 256; // 0x100
- field public static final int DolbyVisionProfileDvavDen = 2; // 0x2
- field public static final int DolbyVisionProfileDvavDer = 1; // 0x1
- field public static final int DolbyVisionProfileDvheDen = 4; // 0x4
- field public static final int DolbyVisionProfileDvheDer = 3; // 0x3
- field public static final int DolbyVisionProfileDvheDtr = 5; // 0x5
- field public static final int DolbyVisionProfileDvheStn = 6; // 0x6
+ field public static final int DolbyVisionProfileDvavPen = 2; // 0x2
+ field public static final int DolbyVisionProfileDvavPer = 1; // 0x1
+ field public static final int DolbyVisionProfileDvheDen = 8; // 0x8
+ field public static final int DolbyVisionProfileDvheDer = 4; // 0x4
+ field public static final int DolbyVisionProfileDvheDth = 64; // 0x40
+ field public static final int DolbyVisionProfileDvheDtr = 16; // 0x10
+ field public static final int DolbyVisionProfileDvheStn = 32; // 0x20
field public static final int H263Level10 = 1; // 0x1
field public static final int H263Level20 = 2; // 0x2
field public static final int H263Level30 = 4; // 0x4
@@ -24659,6 +24621,7 @@
method public android.media.tv.TvInputInfo.Builder setHdmiDeviceInfo(android.hardware.hdmi.HdmiDeviceInfo);
method public android.media.tv.TvInputInfo.Builder setIcon(android.graphics.drawable.Icon);
method public android.media.tv.TvInputInfo.Builder setIcon(android.graphics.drawable.Icon, int);
+ method public android.media.tv.TvInputInfo.Builder setLabel(java.lang.CharSequence);
method public android.media.tv.TvInputInfo.Builder setLabel(int);
method public android.media.tv.TvInputInfo.Builder setParentId(java.lang.String);
method public android.media.tv.TvInputInfo.Builder setTunerCount(int);
@@ -24673,7 +24636,7 @@
}
public final class TvInputManager {
- method public android.media.tv.TvInputManager.Hardware acquireTvInputHardware(int, android.media.tv.TvInputManager.HardwareCallback, android.media.tv.TvInputInfo);
+ method public android.media.tv.TvInputManager.Hardware acquireTvInputHardware(int, android.media.tv.TvInputInfo, android.media.tv.TvInputManager.HardwareCallback);
method public void addBlockedRating(android.media.tv.TvContentRating);
method public boolean captureFrame(java.lang.String, android.view.Surface, android.media.tv.TvStreamConfig);
method public java.util.List<android.media.tv.TvStreamConfig> getAvailableTvStreamConfigList(java.lang.String);
@@ -26805,7 +26768,9 @@
method public void configureWifiChange(android.net.wifi.WifiScanner.WifiChangeSettings);
method public boolean getScanResults();
method public void startBackgroundScan(android.net.wifi.WifiScanner.ScanSettings, android.net.wifi.WifiScanner.ScanListener);
+ method public void startBackgroundScan(android.net.wifi.WifiScanner.ScanSettings, android.net.wifi.WifiScanner.ScanListener, android.os.WorkSource);
method public void startScan(android.net.wifi.WifiScanner.ScanSettings, android.net.wifi.WifiScanner.ScanListener);
+ method public void startScan(android.net.wifi.WifiScanner.ScanSettings, android.net.wifi.WifiScanner.ScanListener, android.os.WorkSource);
method public void startTrackingBssids(android.net.wifi.WifiScanner.BssidInfo[], int, android.net.wifi.WifiScanner.BssidListener);
method public void startTrackingWifiChange(android.net.wifi.WifiScanner.WifiChangeListener);
method public void stopBackgroundScan(android.net.wifi.WifiScanner.ScanListener);
@@ -30984,6 +30949,7 @@
field public static final int TEMPERATURE_CURRENT = 0; // 0x0
field public static final int TEMPERATURE_SHUTDOWN = 2; // 0x2
field public static final int TEMPERATURE_THROTTLING = 1; // 0x1
+ field public static final int TEMPERATURE_THROTTLING_BELOW_VR_MIN = 3; // 0x3
field public static final float UNDEFINED_TEMPERATURE = -3.4028235E38f;
}
@@ -31344,6 +31310,7 @@
method public boolean isPowerSaveMode();
method public boolean isScreenBrightnessBoosted();
method public deprecated boolean isScreenOn();
+ method public boolean isSustainedPerformanceModeSupported();
method public boolean isWakeLockLevelSupported(int);
method public android.os.PowerManager.WakeLock newWakeLock(int, java.lang.String);
method public void reboot(java.lang.String);
@@ -31359,6 +31326,7 @@
field public static final int RELEASE_FLAG_WAIT_FOR_NO_PROXIMITY = 1; // 0x1
field public static final deprecated int SCREEN_BRIGHT_WAKE_LOCK = 10; // 0xa
field public static final deprecated int SCREEN_DIM_WAKE_LOCK = 6; // 0x6
+ field public static final int SUSTAINED_PERFORMANCE_WAKE_LOCK = 256; // 0x100
field public static final int USER_ACTIVITY_EVENT_ACCESSIBILITY = 3; // 0x3
field public static final int USER_ACTIVITY_EVENT_BUTTON = 1; // 0x1
field public static final int USER_ACTIVITY_EVENT_OTHER = 0; // 0x0
@@ -31572,12 +31540,13 @@
public class UpdateEngine {
ctor public UpdateEngine();
- method public void applyPayload(java.lang.String, long, long, java.lang.String[]) throws android.os.RemoteException;
- method public boolean bind(android.os.UpdateEngineCallback, android.os.Handler) throws android.os.RemoteException;
- method public boolean bind(android.os.UpdateEngineCallback) throws android.os.RemoteException;
- method public void cancel() throws android.os.RemoteException;
- method public void resume() throws android.os.RemoteException;
- method public void suspend() throws android.os.RemoteException;
+ method public void applyPayload(java.lang.String, long, long, java.lang.String[]);
+ method public boolean bind(android.os.UpdateEngineCallback, android.os.Handler);
+ method public boolean bind(android.os.UpdateEngineCallback);
+ method public void cancel();
+ method public void resetStatus();
+ method public void resume();
+ method public void suspend();
}
public static final class UpdateEngine.ErrorCodeConstants {
@@ -31783,7 +31752,7 @@
method public android.os.health.HealthStats[] takeUidSnapshots(int[]);
}
- public class TimerStat implements android.os.Parcelable {
+ public final class TimerStat implements android.os.Parcelable {
ctor public TimerStat();
ctor public TimerStat(int, long);
ctor public TimerStat(android.os.Parcel);
@@ -32039,7 +32008,6 @@
method protected void onClick();
method protected android.view.View onCreateView(android.view.ViewGroup);
method public void onDependencyChanged(android.preference.Preference, boolean);
- method protected void onDetachedFromActivity();
method protected java.lang.Object onGetDefaultValue(android.content.res.TypedArray, int);
method public void onParentChanged(android.preference.Preference, boolean);
method protected void onPrepareForRemoval();
@@ -32672,7 +32640,7 @@
method public final boolean isDestroyed();
method public final boolean isPrinterDiscoveryStarted();
method public abstract void onDestroy();
- method public void onRequestCustomPrinterIcon(android.print.PrinterId, android.printservice.CustomPrinterIconCallback);
+ method public void onRequestCustomPrinterIcon(android.print.PrinterId, android.os.CancellationSignal, android.printservice.CustomPrinterIconCallback);
method public abstract void onStartPrinterDiscovery(java.util.List<android.print.PrinterId>);
method public abstract void onStartPrinterStateTracking(android.print.PrinterId);
method public abstract void onStopPrinterDiscovery();
@@ -32683,6 +32651,29 @@
}
+package android.printservice.recommendation {
+
+ public final class RecommendationInfo implements android.os.Parcelable {
+ ctor public RecommendationInfo(java.lang.CharSequence, java.lang.CharSequence, int, boolean);
+ method public int describeContents();
+ method public java.lang.CharSequence getName();
+ method public int getNumDiscoveredPrinters();
+ method public java.lang.CharSequence getPackageName();
+ method public boolean recommendsMultiVendorService();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.printservice.recommendation.RecommendationInfo> CREATOR;
+ }
+
+ public abstract class RecommendationService extends android.app.Service {
+ ctor public RecommendationService();
+ method public final android.os.IBinder onBind(android.content.Intent);
+ method public abstract void onConnected();
+ method public abstract void onDisconnected();
+ method public final void updateRecommendations(java.util.List<android.printservice.recommendation.RecommendationInfo>);
+ }
+
+}
+
package android.provider {
public final class AlarmClock {
@@ -33078,6 +33069,7 @@
field public static final int REJECTED_TYPE = 5; // 0x5
field public static final java.lang.String TRANSCRIPTION = "transcription";
field public static final java.lang.String TYPE = "type";
+ field public static final java.lang.String VIA_NUMBER = "via_number";
field public static final int VOICEMAIL_TYPE = 4; // 0x4
field public static final java.lang.String VOICEMAIL_URI = "voicemail_uri";
}
@@ -34258,6 +34250,7 @@
field public static final java.lang.String EXTRA_EXCLUDE_SELF = "android.provider.extra.EXCLUDE_SELF";
field public static final java.lang.String EXTRA_INFO = "info";
field public static final java.lang.String EXTRA_LOADING = "loading";
+ field public static final java.lang.String EXTRA_ORIENTATION = "android.provider.extra.ORIENTATION";
field public static final java.lang.String EXTRA_PROMPT = "android.provider.extra.PROMPT";
field public static final java.lang.String PROVIDER_INTERFACE = "android.content.action.DOCUMENTS_PROVIDER";
}
@@ -39416,6 +39409,7 @@
field public static final java.lang.String KEY_CARRIER_VT_AVAILABLE_BOOL = "carrier_vt_available_bool";
field public static final java.lang.String KEY_CARRIER_VVM_PACKAGE_NAME_STRING = "carrier_vvm_package_name_string";
field public static final java.lang.String KEY_CARRIER_WFC_IMS_AVAILABLE_BOOL = "carrier_wfc_ims_available_bool";
+ field public static final java.lang.String KEY_CARRIER_WFC_SUPPORTS_WIFI_ONLY_BOOL = "carrier_wfc_supports_wifi_only_bool";
field public static final java.lang.String KEY_CDMA_DTMF_TONE_DELAY_INT = "cdma_dtmf_tone_delay_int";
field public static final java.lang.String KEY_CDMA_NONROAMING_NETWORKS_STRING_ARRAY = "cdma_nonroaming_networks_string_array";
field public static final java.lang.String KEY_CDMA_ROAMING_NETWORKS_STRING_ARRAY = "cdma_roaming_networks_string_array";
@@ -40011,7 +40005,8 @@
method public java.lang.String getDeviceSoftwareVersion();
method public java.lang.String getGroupIdLevel1();
method public java.lang.String getGroupIdLevel1(int);
- method public java.lang.String getIccSimChallengeResponse(int, java.lang.String);
+ method public java.lang.String getIccAuthentication(int, int, java.lang.String);
+ method public java.lang.String getIccAuthentication(int, int, int, java.lang.String);
method public java.lang.String getLine1AlphaTag(int);
method public java.lang.String getLine1Number();
method public java.lang.String getLine1Number(int);
@@ -40101,6 +40096,13 @@
field public static final java.lang.String ACTION_PHONE_STATE_CHANGED = "android.intent.action.PHONE_STATE";
field public static final java.lang.String ACTION_RESPOND_VIA_MESSAGE = "android.intent.action.RESPOND_VIA_MESSAGE";
field public static final java.lang.String ACTION_SHOW_VOICEMAIL_NOTIFICATION = "android.telephony.action.SHOW_VOICEMAIL_NOTIFICATION";
+ field public static final int APPTYPE_CSIM = 4; // 0x4
+ field public static final int APPTYPE_ISIM = 5; // 0x5
+ field public static final int APPTYPE_RUIM = 3; // 0x3
+ field public static final int APPTYPE_SIM = 1; // 0x1
+ field public static final int APPTYPE_USIM = 2; // 0x2
+ field public static final int AUTHTYPE_EAP_AKA = 129; // 0x81
+ field public static final int AUTHTYPE_EAP_SIM = 128; // 0x80
field public static final int CALL_STATE_IDLE = 0; // 0x0
field public static final int CALL_STATE_OFFHOOK = 2; // 0x2
field public static final int CALL_STATE_RINGING = 1; // 0x1
@@ -40658,8 +40660,6 @@
method public java.lang.String getPackageResourcePath();
method public android.content.res.Resources getResources();
method public android.content.SharedPreferences getSharedPreferences(java.lang.String, int);
- method public android.content.SharedPreferences getSharedPreferences(java.io.File, int);
- method public java.io.File getSharedPreferencesPath(java.lang.String);
method public java.lang.Object getSystemService(java.lang.String);
method public java.lang.String getSystemServiceName(java.lang.Class<?>);
method public android.content.res.Resources.Theme getTheme();
@@ -45024,6 +45024,7 @@
method public boolean dispatchDragEvent(android.view.DragEvent);
method protected void dispatchDraw(android.graphics.Canvas);
method public void dispatchDrawableHotspotChanged(float, float);
+ method public void dispatchFinishTemporaryDetach();
method protected boolean dispatchGenericFocusedEvent(android.view.MotionEvent);
method public boolean dispatchGenericMotionEvent(android.view.MotionEvent);
method protected boolean dispatchGenericPointerEvent(android.view.MotionEvent);
@@ -45043,6 +45044,7 @@
method protected void dispatchSetActivated(boolean);
method protected void dispatchSetPressed(boolean);
method protected void dispatchSetSelected(boolean);
+ method public void dispatchStartTemporaryDetach();
method public void dispatchSystemUiVisibilityChanged(int);
method public boolean dispatchTouchEvent(android.view.MotionEvent);
method public boolean dispatchTrackballEvent(android.view.MotionEvent);
@@ -45060,6 +45062,7 @@
method public void findViewsWithText(java.util.ArrayList<android.view.View>, java.lang.CharSequence, int);
method protected deprecated boolean fitSystemWindows(android.graphics.Rect);
method public android.view.View focusSearch(int);
+ method public void forceHasOverlappingRendering(boolean);
method public void forceLayout();
method public static int generateViewId();
method public java.lang.CharSequence getAccessibilityClassName();
@@ -45105,6 +45108,7 @@
method public boolean getGlobalVisibleRect(android.graphics.Rect, android.graphics.Point);
method public final boolean getGlobalVisibleRect(android.graphics.Rect);
method public android.os.Handler getHandler();
+ method public final boolean getHasOverlappingRendering();
method public final int getHeight();
method public void getHitRect(android.graphics.Rect);
method public int getHorizontalFadingEdgeLength();
@@ -45253,6 +45257,7 @@
method public boolean isSelected();
method public boolean isShown();
method public boolean isSoundEffectsEnabled();
+ method public final boolean isTemporarilyDetached();
method public boolean isTextAlignmentResolved();
method public boolean isTextDirectionResolved();
method public boolean isVerticalFadingEdgeEnabled();
@@ -47012,6 +47017,7 @@
public final class AccessibilityWindowInfo implements android.os.Parcelable {
method public int describeContents();
+ method public android.view.accessibility.AccessibilityNodeInfo getAnchor();
method public void getBoundsInScreen(android.graphics.Rect);
method public android.view.accessibility.AccessibilityWindowInfo getChild(int);
method public int getChildCount();
@@ -47019,6 +47025,7 @@
method public int getLayer();
method public android.view.accessibility.AccessibilityWindowInfo getParent();
method public android.view.accessibility.AccessibilityNodeInfo getRoot();
+ method public java.lang.CharSequence getTitle();
method public int getType();
method public boolean isAccessibilityFocused();
method public boolean isActive();
@@ -47359,6 +47366,7 @@
ctor public BaseInputConnection(android.view.View, boolean);
method public boolean beginBatchEdit();
method public boolean clearMetaKeyStates(int);
+ method public void closeConnection();
method public boolean commitCompletion(android.view.inputmethod.CompletionInfo);
method public boolean commitCorrection(android.view.inputmethod.CorrectionInfo);
method public boolean commitText(java.lang.CharSequence, int);
@@ -47526,6 +47534,7 @@
public abstract interface InputConnection {
method public abstract boolean beginBatchEdit();
method public abstract boolean clearMetaKeyStates(int);
+ method public abstract void closeConnection();
method public abstract boolean commitCompletion(android.view.inputmethod.CompletionInfo);
method public abstract boolean commitCorrection(android.view.inputmethod.CorrectionInfo);
method public abstract boolean commitText(java.lang.CharSequence, int);
@@ -47558,6 +47567,7 @@
ctor public InputConnectionWrapper(android.view.inputmethod.InputConnection, boolean);
method public boolean beginBatchEdit();
method public boolean clearMetaKeyStates(int);
+ method public void closeConnection();
method public boolean commitCompletion(android.view.inputmethod.CompletionInfo);
method public boolean commitCorrection(android.view.inputmethod.CorrectionInfo);
method public boolean commitText(java.lang.CharSequence, int);
@@ -48651,6 +48661,7 @@
method public int getPackageId(android.content.res.Resources, java.lang.String);
method public void invokeDrawGlFunctor(android.view.View, long, boolean);
method public boolean isTraceTagEnabled();
+ method public java.lang.Runnable setDrawGlFunctionDetachedCallback(android.view.View, java.lang.Runnable);
method public void setOnTraceEnabledChangeListener(android.webkit.WebViewDelegate.OnTraceEnabledChangeListener);
}
@@ -48661,7 +48672,6 @@
public final class WebViewFactory {
ctor public WebViewFactory();
method public static android.content.pm.PackageInfo getLoadedPackageInfo();
- method public static java.lang.String getWebViewPackageName();
method public static int loadWebViewNativeLibraryFromPackage(java.lang.String, java.lang.ClassLoader);
method public static void prepareWebViewInZygote();
field public static final java.lang.String CHROMIUM_WEBVIEW_VMSIZE_SIZE_PROPERTY = "persist.sys.webview.vmsize";
@@ -48857,6 +48867,24 @@
method public abstract boolean shouldDelayChildPressedState();
}
+ public final class WebViewProviderInfo implements android.os.Parcelable {
+ ctor public WebViewProviderInfo(java.lang.String, java.lang.String, boolean, boolean, java.lang.String[]);
+ method public int describeContents();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.webkit.WebViewProviderInfo> CREATOR;
+ field public final boolean availableByDefault;
+ field public final java.lang.String description;
+ field public final boolean isFallback;
+ field public final java.lang.String packageName;
+ field public final java.lang.String[] signatures;
+ }
+
+ public final class WebViewUpdateService {
+ method public static android.webkit.WebViewProviderInfo[] getAllWebViewPackages();
+ method public static java.lang.String getCurrentWebViewPackageName();
+ method public static android.webkit.WebViewProviderInfo[] getValidWebViewPackages();
+ }
+
}
package android.widget {
@@ -51341,9 +51369,15 @@
method public void collapseActionView();
method public void dismissPopupMenus();
method public int getContentInsetEnd();
+ method public int getContentInsetEndWithActions();
method public int getContentInsetLeft();
method public int getContentInsetRight();
method public int getContentInsetStart();
+ method public int getContentInsetStartWithNavigation();
+ method public int getCurrentContentInsetEnd();
+ method public int getCurrentContentInsetLeft();
+ method public int getCurrentContentInsetRight();
+ method public int getCurrentContentInsetStart();
method public android.graphics.drawable.Drawable getLogo();
method public java.lang.CharSequence getLogoDescription();
method public android.view.Menu getMenu();
@@ -51362,6 +51396,8 @@
method public void inflateMenu(int);
method public boolean isOverflowMenuShowing();
method protected void onLayout(boolean, int, int, int, int);
+ method public void setContentInsetEndWithActions(int);
+ method public void setContentInsetStartWithNavigation(int);
method public void setContentInsetsAbsolute(int, int);
method public void setContentInsetsRelative(int, int);
method public void setLogo(int);
@@ -52346,9 +52382,7 @@
public final class FilePermission extends java.security.Permission implements java.io.Serializable {
ctor public FilePermission(java.lang.String, java.lang.String);
- method public boolean equals(java.lang.Object);
method public java.lang.String getActions();
- method public int hashCode();
method public boolean implies(java.security.Permission);
}
@@ -53087,6 +53121,7 @@
method public static int compare(boolean, boolean);
method public int compareTo(java.lang.Boolean);
method public static boolean getBoolean(java.lang.String);
+ method public static int hashCode(boolean);
method public static boolean parseBoolean(java.lang.String);
method public static java.lang.String toString(boolean);
method public static java.lang.Boolean valueOf(boolean);
@@ -53104,6 +53139,7 @@
method public static java.lang.Byte decode(java.lang.String) throws java.lang.NumberFormatException;
method public double doubleValue();
method public float floatValue();
+ method public static int hashCode(byte);
method public int intValue();
method public long longValue();
method public static byte parseByte(java.lang.String, int) throws java.lang.NumberFormatException;
@@ -53112,6 +53148,7 @@
method public static java.lang.Byte valueOf(byte);
method public static java.lang.Byte valueOf(java.lang.String, int) throws java.lang.NumberFormatException;
method public static java.lang.Byte valueOf(java.lang.String) throws java.lang.NumberFormatException;
+ field public static final int BYTES = 1; // 0x1
field public static final byte MAX_VALUE = 127; // 0x7f
field public static final byte MIN_VALUE = -128; // 0xffffff80
field public static final int SIZE = 8; // 0x8
@@ -53149,6 +53186,7 @@
method public static int getNumericValue(int);
method public static int getType(char);
method public static int getType(int);
+ method public static int hashCode(char);
method public static char highSurrogate(int);
method public static boolean isAlphabetic(int);
method public static boolean isBmpCodePoint(int);
@@ -53209,6 +53247,7 @@
method public static char toUpperCase(char);
method public static int toUpperCase(int);
method public static java.lang.Character valueOf(char);
+ field public static final int BYTES = 2; // 0x2
field public static final byte COMBINING_SPACING_MARK = 8; // 0x8
field public static final byte CONNECTOR_PUNCTUATION = 23; // 0x17
field public static final byte CONTROL = 15; // 0xf
@@ -53835,6 +53874,7 @@
method public static int floatToIntBits(float);
method public static int floatToRawIntBits(float);
method public float floatValue();
+ method public static int hashCode(float);
method public static float intBitsToFloat(int);
method public int intValue();
method public static boolean isFinite(float);
@@ -53843,11 +53883,15 @@
method public static boolean isNaN(float);
method public boolean isNaN();
method public long longValue();
+ method public static float max(float, float);
+ method public static float min(float, float);
method public static float parseFloat(java.lang.String) throws java.lang.NumberFormatException;
+ method public static float sum(float, float);
method public static java.lang.String toHexString(float);
method public static java.lang.String toString(float);
method public static java.lang.Float valueOf(java.lang.String) throws java.lang.NumberFormatException;
method public static java.lang.Float valueOf(float);
+ field public static final int BYTES = 4; // 0x4
field public static final int MAX_EXPONENT = 127; // 0x7f
field public static final float MAX_VALUE = 3.4028235E38f;
field public static final int MIN_EXPONENT = -126; // 0xffffff82
@@ -54027,6 +54071,7 @@
method public static java.lang.Long valueOf(java.lang.String, int) throws java.lang.NumberFormatException;
method public static java.lang.Long valueOf(java.lang.String) throws java.lang.NumberFormatException;
method public static java.lang.Long valueOf(long);
+ field public static final int BYTES = 8; // 0x8
field public static final long MAX_VALUE = 9223372036854775807L; // 0x7fffffffffffffffL
field public static final long MIN_VALUE = -9223372036854775808L; // 0x8000000000000000L
field public static final int SIZE = 64; // 0x40
@@ -54330,6 +54375,7 @@
method public static java.lang.Short decode(java.lang.String) throws java.lang.NumberFormatException;
method public double doubleValue();
method public float floatValue();
+ method public static int hashCode(short);
method public int intValue();
method public long longValue();
method public static short parseShort(java.lang.String, int) throws java.lang.NumberFormatException;
@@ -54339,6 +54385,7 @@
method public static java.lang.Short valueOf(java.lang.String, int) throws java.lang.NumberFormatException;
method public static java.lang.Short valueOf(java.lang.String) throws java.lang.NumberFormatException;
method public static java.lang.Short valueOf(short);
+ field public static final int BYTES = 2; // 0x2
field public static final short MAX_VALUE = 32767; // 0x7fff
field public static final short MIN_VALUE = -32768; // 0xffff8000
field public static final int SIZE = 16; // 0x10
@@ -55862,9 +55909,7 @@
public final class SocketPermission extends java.security.Permission implements java.io.Serializable {
ctor public SocketPermission(java.lang.String, java.lang.String);
- method public boolean equals(java.lang.Object);
method public java.lang.String getActions();
- method public int hashCode();
method public boolean implies(java.security.Permission);
}
@@ -56946,9 +56991,7 @@
public final class AllPermission extends java.security.Permission {
ctor public AllPermission();
ctor public AllPermission(java.lang.String, java.lang.String);
- method public boolean equals(java.lang.Object);
method public java.lang.String getActions();
- method public int hashCode();
method public boolean implies(java.security.Permission);
}
@@ -56962,9 +57005,7 @@
public abstract class BasicPermission extends java.security.Permission implements java.io.Serializable {
ctor public BasicPermission(java.lang.String);
ctor public BasicPermission(java.lang.String, java.lang.String);
- method public boolean equals(java.lang.Object);
method public java.lang.String getActions();
- method public int hashCode();
method public boolean implies(java.security.Permission);
}
@@ -57342,10 +57383,8 @@
public abstract class Permission implements java.security.Guard java.io.Serializable {
ctor public Permission(java.lang.String);
method public void checkGuard(java.lang.Object) throws java.lang.SecurityException;
- method public abstract boolean equals(java.lang.Object);
method public abstract java.lang.String getActions();
method public final java.lang.String getName();
- method public abstract int hashCode();
method public abstract boolean implies(java.security.Permission);
method public java.security.PermissionCollection newPermissionCollection();
}
@@ -57603,13 +57642,11 @@
public final class UnresolvedPermission extends java.security.Permission implements java.io.Serializable {
ctor public UnresolvedPermission(java.lang.String, java.lang.String, java.lang.String, java.security.cert.Certificate[]);
- method public boolean equals(java.lang.Object);
method public java.lang.String getActions();
method public java.lang.String getUnresolvedActions();
method public java.security.cert.Certificate[] getUnresolvedCerts();
method public java.lang.String getUnresolvedName();
method public java.lang.String getUnresolvedType();
- method public int hashCode();
method public boolean implies(java.security.Permission);
}
@@ -57667,8 +57704,6 @@
}
public abstract interface Permission {
- method public abstract boolean equals(java.lang.Object);
- method public abstract java.lang.String toString();
}
}
@@ -60384,6 +60419,7 @@
method public void forEach(java.util.function.Consumer<? super E>);
method public E get(int);
method public boolean removeIf(java.util.function.Predicate<? super E>);
+ method public void replaceAll(java.util.function.UnaryOperator<E>);
method public int size();
method public void sort(java.util.Comparator<? super E>);
method public java.util.Spliterator<E> spliterator();
@@ -60469,6 +60505,10 @@
method public static int hashCode(float[]);
method public static int hashCode(double[]);
method public static int hashCode(java.lang.Object[]);
+ method public static void parallelSetAll(T[], java.util.function.IntFunction<? extends T>);
+ method public static void parallelSetAll(int[], java.util.function.IntUnaryOperator);
+ method public static void parallelSetAll(long[], java.util.function.IntToLongFunction);
+ method public static void parallelSetAll(double[], java.util.function.IntToDoubleFunction);
method public static void parallelSort(byte[]);
method public static void parallelSort(byte[], int, int);
method public static void parallelSort(char[]);
@@ -61017,6 +61057,7 @@
method public java.lang.Object clone();
method public java.util.Set<java.util.Map.Entry<K, V>> entrySet();
method public void forEach(java.util.function.BiConsumer<? super K, ? super V>);
+ method public boolean replace(K, V, V);
}
public class HashSet extends java.util.AbstractSet implements java.lang.Cloneable java.io.Serializable java.util.Set {
@@ -61037,6 +61078,9 @@
ctor public Hashtable(java.util.Map<? extends K, ? extends V>);
method public synchronized void clear();
method public synchronized java.lang.Object clone();
+ method public synchronized V compute(K, java.util.function.BiFunction<? super K, ? super V, ? extends V>);
+ method public synchronized V computeIfAbsent(K, java.util.function.Function<? super K, ? extends V>);
+ method public synchronized V computeIfPresent(K, java.util.function.BiFunction<? super K, ? super V, ? extends V>);
method public synchronized boolean contains(java.lang.Object);
method public synchronized boolean containsKey(java.lang.Object);
method public boolean containsValue(java.lang.Object);
@@ -61044,13 +61088,19 @@
method public java.util.Set<java.util.Map.Entry<K, V>> entrySet();
method public synchronized void forEach(java.util.function.BiConsumer<? super K, ? super V>);
method public synchronized V get(java.lang.Object);
+ method public synchronized V getOrDefault(java.lang.Object, V);
method public synchronized boolean isEmpty();
method public java.util.Set<K> keySet();
method public synchronized java.util.Enumeration<K> keys();
+ method public synchronized V merge(K, V, java.util.function.BiFunction<? super V, ? super V, ? extends V>);
method public synchronized V put(K, V);
method public synchronized void putAll(java.util.Map<? extends K, ? extends V>);
+ method public synchronized V putIfAbsent(K, V);
method protected void rehash();
method public synchronized V remove(java.lang.Object);
+ method public synchronized boolean remove(java.lang.Object, java.lang.Object);
+ method public synchronized boolean replace(K, V, V);
+ method public synchronized V replace(K, V);
method public synchronized int size();
method public java.util.Collection<V> values();
}
@@ -61195,9 +61245,11 @@
method public abstract boolean remove(java.lang.Object);
method public abstract E remove(int);
method public abstract boolean removeAll(java.util.Collection<?>);
+ method public default void replaceAll(java.util.function.UnaryOperator<E>);
method public abstract boolean retainAll(java.util.Collection<?>);
method public abstract E set(int, E);
method public abstract int size();
+ method public default void sort(java.util.Comparator<? super E>);
method public abstract java.util.List<E> subList(int, int);
method public abstract java.lang.Object[] toArray();
method public abstract T[] toArray(T[]);
@@ -62112,9 +62164,11 @@
method public synchronized boolean removeElement(java.lang.Object);
method public synchronized void removeElementAt(int);
method public synchronized boolean removeIf(java.util.function.Predicate<? super E>);
+ method public synchronized void replaceAll(java.util.function.UnaryOperator<E>);
method public synchronized void setElementAt(E, int);
method public synchronized void setSize(int);
method public synchronized int size();
+ method public synchronized void sort(java.util.Comparator<? super E>);
method public java.util.Spliterator<E> spliterator();
method public synchronized void trimToSize();
field protected int capacityIncrement;
@@ -62580,6 +62634,7 @@
method public java.lang.Object clone();
method public boolean contains(java.lang.Object);
method public boolean containsAll(java.util.Collection<?>);
+ method public void forEach(java.util.function.Consumer<? super E>);
method public E get(int);
method public int indexOf(E, int);
method public int indexOf(java.lang.Object);
@@ -66957,11 +67012,9 @@
public final class PrivateCredentialPermission extends java.security.Permission {
ctor public PrivateCredentialPermission(java.lang.String, java.lang.String);
- method public boolean equals(java.lang.Object);
method public java.lang.String getActions();
method public java.lang.String getCredentialClass();
method public java.lang.String[][] getPrincipals();
- method public int hashCode();
method public boolean implies(java.security.Permission);
}
diff --git a/api/system-removed.txt b/api/system-removed.txt
index bc17627..03cf8b0 100644
--- a/api/system-removed.txt
+++ b/api/system-removed.txt
@@ -92,6 +92,10 @@
package android.media.tv {
+ public final class TvInputManager {
+ method public android.media.tv.TvInputManager.Hardware acquireTvInputHardware(int, android.media.tv.TvInputManager.HardwareCallback, android.media.tv.TvInputInfo);
+ }
+
public class TvView extends android.view.ViewGroup {
method public void requestUnblockContent(android.media.tv.TvContentRating);
}
diff --git a/api/test-current.txt b/api/test-current.txt
index 39b0dac..d495d9f 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -71,6 +71,7 @@
field public static final java.lang.String GET_ACCOUNTS = "android.permission.GET_ACCOUNTS";
field public static final java.lang.String GET_ACCOUNTS_PRIVILEGED = "android.permission.GET_ACCOUNTS_PRIVILEGED";
field public static final java.lang.String GET_PACKAGE_SIZE = "android.permission.GET_PACKAGE_SIZE";
+ field public static final java.lang.String GET_PASSWORD_PRIVILEGED = "android.permission.GET_PASSWORD_PRIVILEGED";
field public static final deprecated java.lang.String GET_TASKS = "android.permission.GET_TASKS";
field public static final java.lang.String GLOBAL_SEARCH = "android.permission.GLOBAL_SEARCH";
field public static final java.lang.String INSTALL_LOCATION_PROVIDER = "android.permission.INSTALL_LOCATION_PROVIDER";
@@ -301,13 +302,13 @@
field public static final int backgroundTint = 16843883; // 0x101046b
field public static final int backgroundTintMode = 16843884; // 0x101046c
field public static final int backupAgent = 16843391; // 0x101027f
- field public static final int backupInForeground = 16844060; // 0x101051c
+ field public static final int backupInForeground = 16844059; // 0x101051b
field public static final int banner = 16843762; // 0x10103f2
field public static final int baseline = 16843548; // 0x101031c
field public static final int baselineAlignBottom = 16843042; // 0x1010122
field public static final int baselineAligned = 16843046; // 0x1010126
field public static final int baselineAlignedChildIndex = 16843047; // 0x1010127
- field public static final int bitmap = 16844056; // 0x1010518
+ field public static final int bitmap = 16844055; // 0x1010517
field public static final int borderlessButtonStyle = 16843563; // 0x101032b
field public static final int bottom = 16843184; // 0x10101b0
field public static final int bottomBright = 16842957; // 0x10100cd
@@ -326,7 +327,7 @@
field public static final int buttonBarNeutralButtonStyle = 16843914; // 0x101048a
field public static final int buttonBarPositiveButtonStyle = 16843913; // 0x1010489
field public static final int buttonBarStyle = 16843566; // 0x101032e
- field public static final int buttonGravity = 16844032; // 0x1010500
+ field public static final int buttonGravity = 16844031; // 0x10104ff
field public static final int buttonStyle = 16842824; // 0x1010048
field public static final int buttonStyleInset = 16842826; // 0x101004a
field public static final int buttonStyleSmall = 16842825; // 0x1010049
@@ -337,9 +338,9 @@
field public static final int calendarTextColor = 16843931; // 0x101049b
field public static final int calendarViewShown = 16843596; // 0x101034c
field public static final int calendarViewStyle = 16843613; // 0x101035d
- field public static final int canControlMagnification = 16844041; // 0x1010509
- field public static final int canPerformGestures = 16844047; // 0x101050f
- field public static final int canRecord = 16844062; // 0x101051e
+ field public static final int canControlMagnification = 16844040; // 0x1010508
+ field public static final int canPerformGestures = 16844046; // 0x101050e
+ field public static final int canRecord = 16844061; // 0x101051d
field public static final int canRequestEnhancedWebAccessibility = 16843736; // 0x10103d8
field public static final int canRequestFilterKeyEvents = 16843737; // 0x10103d9
field public static final int canRequestTouchExplorationMode = 16843735; // 0x10103d7
@@ -379,7 +380,7 @@
field public static final int codes = 16843330; // 0x1010242
field public static final int collapseColumns = 16843083; // 0x101014b
field public static final int collapseContentDescription = 16843984; // 0x10104d0
- field public static final int collapseIcon = 16844033; // 0x1010501
+ field public static final int collapseIcon = 16844032; // 0x1010500
field public static final int color = 16843173; // 0x10101a5
field public static final int colorAccent = 16843829; // 0x1010435
field public static final int colorActivatedHighlight = 16843664; // 0x1010390
@@ -416,16 +417,18 @@
field public static final int contentAuthority = 16843408; // 0x1010290
field public static final int contentDescription = 16843379; // 0x1010273
field public static final int contentInsetEnd = 16843860; // 0x1010454
+ field public static final int contentInsetEndWithActions = 16844070; // 0x1010526
field public static final int contentInsetLeft = 16843861; // 0x1010455
field public static final int contentInsetRight = 16843862; // 0x1010456
field public static final int contentInsetStart = 16843859; // 0x1010453
+ field public static final int contentInsetStartWithNavigation = 16844069; // 0x1010525
field public static final int contextClickable = 16844007; // 0x10104e7
- field public static final int contextPopupMenuStyle = 16844035; // 0x1010503
+ field public static final int contextPopupMenuStyle = 16844034; // 0x1010502
field public static final int controlX1 = 16843772; // 0x10103fc
field public static final int controlX2 = 16843774; // 0x10103fe
field public static final int controlY1 = 16843773; // 0x10103fd
field public static final int controlY2 = 16843775; // 0x10103ff
- field public static final int countDown = 16844061; // 0x101051d
+ field public static final int countDown = 16844060; // 0x101051c
field public static final int country = 16843962; // 0x10104ba
field public static final int cropToPadding = 16843043; // 0x1010123
field public static final int cursorVisible = 16843090; // 0x1010152
@@ -443,7 +446,7 @@
field public static final deprecated int dayOfWeekTextAppearance = 16843925; // 0x1010495
field public static final int debuggable = 16842767; // 0x101000f
field public static final int defaultHeight = 16844021; // 0x10104f5
- field public static final int defaultToDeviceProtectedStorage = 16844038; // 0x1010506
+ field public static final int defaultToDeviceProtectedStorage = 16844037; // 0x1010505
field public static final int defaultValue = 16843245; // 0x10101ed
field public static final int defaultWidth = 16844020; // 0x10104f4
field public static final int delay = 16843212; // 0x10101cc
@@ -463,7 +466,7 @@
field public static final int dialogTheme = 16843528; // 0x1010308
field public static final int dialogTitle = 16843250; // 0x10101f2
field public static final int digits = 16843110; // 0x1010166
- field public static final int directBootAware = 16844039; // 0x1010507
+ field public static final int directBootAware = 16844038; // 0x1010506
field public static final int direction = 16843217; // 0x10101d1
field public static final deprecated int directionDescriptions = 16843681; // 0x10103a1
field public static final int directionPriority = 16843218; // 0x10101d2
@@ -514,8 +517,8 @@
field public static final int enabled = 16842766; // 0x101000e
field public static final int end = 16843996; // 0x10104dc
field public static final int endColor = 16843166; // 0x101019e
- field public static final int endX = 16844052; // 0x1010514
- field public static final int endY = 16844053; // 0x1010515
+ field public static final int endX = 16844051; // 0x1010513
+ field public static final int endY = 16844052; // 0x1010514
field public static final deprecated int endYear = 16843133; // 0x101017d
field public static final int enterFadeDuration = 16843532; // 0x101030c
field public static final int entries = 16842930; // 0x10100b2
@@ -535,7 +538,7 @@
field public static final int expandableListViewStyle = 16842863; // 0x101006f
field public static final int expandableListViewWhiteStyle = 16843446; // 0x10102b6
field public static final int exported = 16842768; // 0x1010010
- field public static final int externalService = 16844048; // 0x1010510
+ field public static final int externalService = 16844047; // 0x101050f
field public static final int extraTension = 16843371; // 0x101026b
field public static final int extractNativeLibs = 16844010; // 0x10104ea
field public static final int factor = 16843219; // 0x10101d3
@@ -560,7 +563,7 @@
field public static final int fillBefore = 16843196; // 0x10101bc
field public static final int fillColor = 16843780; // 0x1010404
field public static final int fillEnabled = 16843343; // 0x101024f
- field public static final int fillType = 16844065; // 0x1010521
+ field public static final int fillType = 16844064; // 0x1010520
field public static final int fillViewport = 16843130; // 0x101017a
field public static final int filter = 16843035; // 0x101011b
field public static final int filterTouchesWhenObscured = 16843460; // 0x10102c4
@@ -576,6 +579,7 @@
field public static final int fontFamily = 16843692; // 0x10103ac
field public static final int fontFeatureSettings = 16843959; // 0x10104b7
field public static final int footerDividersEnabled = 16843311; // 0x101022f
+ field public static final int forceHasOverlappingRendering = 16844068; // 0x1010524
field public static final int foreground = 16843017; // 0x1010109
field public static final int foregroundGravity = 16843264; // 0x1010200
field public static final int foregroundTint = 16843885; // 0x101046d
@@ -652,8 +656,8 @@
field public static final int horizontalScrollViewStyle = 16843603; // 0x1010353
field public static final int horizontalSpacing = 16843028; // 0x1010114
field public static final int host = 16842792; // 0x1010028
- field public static final int hotSpotX = 16844057; // 0x1010519
- field public static final int hotSpotY = 16844058; // 0x101051a
+ field public static final int hotSpotX = 16844056; // 0x1010518
+ field public static final int hotSpotY = 16844057; // 0x1010519
field public static final int hyphenationFrequency = 16843998; // 0x10104de
field public static final int icon = 16842754; // 0x1010002
field public static final int iconPreview = 16843337; // 0x1010249
@@ -740,7 +744,7 @@
field public static final int label = 16842753; // 0x1010001
field public static final int labelFor = 16843718; // 0x10103c6
field public static final int labelTextSize = 16843317; // 0x1010235
- field public static final int languageTag = 16844042; // 0x101050a
+ field public static final int languageTag = 16844041; // 0x1010509
field public static final int largeHeap = 16843610; // 0x101035a
field public static final int largeScreens = 16843398; // 0x1010286
field public static final int largestWidthLimitDp = 16843622; // 0x1010366
@@ -798,7 +802,7 @@
field public static final int layout_y = 16843136; // 0x1010180
field public static final int left = 16843181; // 0x10101ad
field public static final int letterSpacing = 16843958; // 0x10104b6
- field public static final int level = 16844034; // 0x1010502
+ field public static final int level = 16844033; // 0x1010501
field public static final int lineSpacingExtra = 16843287; // 0x1010217
field public static final int lineSpacingMultiplier = 16843288; // 0x1010218
field public static final int lines = 16843092; // 0x1010154
@@ -831,7 +835,7 @@
field public static final int marqueeRepeatLimit = 16843293; // 0x101021d
field public static final int matchOrder = 16843855; // 0x101044f
field public static final int max = 16843062; // 0x1010136
- field public static final int maxButtonHeight = 16844031; // 0x10104ff
+ field public static final int maxButtonHeight = 16844030; // 0x10104fe
field public static final int maxDate = 16843584; // 0x1010340
field public static final int maxEms = 16843095; // 0x1010157
field public static final int maxHeight = 16843040; // 0x1010120
@@ -859,7 +863,7 @@
field public static final int minResizeWidth = 16843669; // 0x1010395
field public static final int minSdkVersion = 16843276; // 0x101020c
field public static final int minWidth = 16843071; // 0x101013f
- field public static final int minimalHeight = 16844023; // 0x10104f7
+ field public static final int minimalHeight = 16844067; // 0x1010523
field public static final int minimalWidth = 16844022; // 0x10104f6
field public static final int minimumHorizontalAngle = 16843901; // 0x101047d
field public static final int minimumVerticalAngle = 16843902; // 0x101047e
@@ -881,7 +885,7 @@
field public static final int nextFocusLeft = 16842977; // 0x10100e1
field public static final int nextFocusRight = 16842978; // 0x10100e2
field public static final int nextFocusUp = 16842979; // 0x10100e3
- field public static final int nfcAntennaPositionDrawable = 16844064; // 0x1010520
+ field public static final int nfcAntennaPositionDrawable = 16844063; // 0x101051f
field public static final int noHistory = 16843309; // 0x101022d
field public static final int normalScreens = 16843397; // 0x1010285
field public static final int notificationTimeout = 16843651; // 0x1010383
@@ -893,7 +897,7 @@
field public static final int numbersTextColor = 16843937; // 0x10104a1
field public static final deprecated int numeric = 16843109; // 0x1010165
field public static final int numericShortcut = 16843236; // 0x10101e4
- field public static final int offset = 16844054; // 0x1010516
+ field public static final int offset = 16844053; // 0x1010515
field public static final int onClick = 16843375; // 0x101026f
field public static final int oneshot = 16843159; // 0x1010197
field public static final int opacity = 16843550; // 0x101031e
@@ -940,13 +944,13 @@
field public static final deprecated int phoneNumber = 16843111; // 0x1010167
field public static final int pivotX = 16843189; // 0x10101b5
field public static final int pivotY = 16843190; // 0x10101b6
- field public static final int pointerShape = 16844043; // 0x101050b
+ field public static final int pointerShape = 16844042; // 0x101050a
field public static final int popupAnimationStyle = 16843465; // 0x10102c9
field public static final int popupBackground = 16843126; // 0x1010176
field public static final int popupCharacters = 16843332; // 0x1010244
field public static final int popupElevation = 16843916; // 0x101048c
- field public static final int popupEnterTransition = 16844066; // 0x1010522
- field public static final int popupExitTransition = 16844067; // 0x1010523
+ field public static final int popupEnterTransition = 16844065; // 0x1010521
+ field public static final int popupExitTransition = 16844066; // 0x1010522
field public static final int popupKeyboard = 16843331; // 0x1010243
field public static final int popupLayout = 16843323; // 0x101023b
field public static final int popupMenuStyle = 16843520; // 0x1010300
@@ -955,7 +959,7 @@
field public static final int port = 16842793; // 0x1010029
field public static final int positiveButtonText = 16843253; // 0x10101f5
field public static final int preferenceCategoryStyle = 16842892; // 0x101008c
- field public static final int preferenceFragmentStyle = 16844040; // 0x1010508
+ field public static final int preferenceFragmentStyle = 16844039; // 0x1010507
field public static final int preferenceInformationStyle = 16842893; // 0x101008d
field public static final int preferenceLayoutChild = 16842900; // 0x1010094
field public static final int preferenceScreenStyle = 16842891; // 0x101008b
@@ -1023,7 +1027,7 @@
field public static final int resizeClip = 16843983; // 0x10104cf
field public static final int resizeMode = 16843619; // 0x1010363
field public static final int resizeable = 16843405; // 0x101028d
- field public static final int resizeableActivity = 16844024; // 0x10104f8
+ field public static final int resizeableActivity = 16844023; // 0x10104f7
field public static final int resource = 16842789; // 0x1010025
field public static final int restoreAnyVersion = 16843450; // 0x10102ba
field public static final deprecated int restoreNeedsApplication = 16843421; // 0x101029d
@@ -1143,8 +1147,8 @@
field public static final int startColor = 16843165; // 0x101019d
field public static final int startDelay = 16843746; // 0x10103e2
field public static final int startOffset = 16843198; // 0x10101be
- field public static final int startX = 16844050; // 0x1010512
- field public static final int startY = 16844051; // 0x1010513
+ field public static final int startX = 16844049; // 0x1010511
+ field public static final int startY = 16844050; // 0x1010512
field public static final deprecated int startYear = 16843132; // 0x101017c
field public static final int stateListAnimator = 16843848; // 0x1010448
field public static final int stateNotNeeded = 16842774; // 0x1010016
@@ -1201,8 +1205,8 @@
field public static final int summaryOn = 16843247; // 0x10101ef
field public static final int supportsAssist = 16844016; // 0x10104f0
field public static final int supportsLaunchVoiceAssistFromKeyguard = 16844017; // 0x10104f1
- field public static final int supportsLocalInteraction = 16844049; // 0x1010511
- field public static final int supportsPictureInPicture = 16844025; // 0x10104f9
+ field public static final int supportsLocalInteraction = 16844048; // 0x1010510
+ field public static final int supportsPictureInPicture = 16844024; // 0x10104f8
field public static final int supportsRtl = 16843695; // 0x10103af
field public static final int supportsSwitchingToNextInputMethod = 16843755; // 0x10103eb
field public static final int supportsUploading = 16843419; // 0x101029b
@@ -1251,7 +1255,7 @@
field public static final int textAppearanceListItemSmall = 16843679; // 0x101039f
field public static final int textAppearanceMedium = 16842817; // 0x1010041
field public static final int textAppearanceMediumInverse = 16842820; // 0x1010044
- field public static final int textAppearancePopupMenuHeader = 16844036; // 0x1010504
+ field public static final int textAppearancePopupMenuHeader = 16844035; // 0x1010503
field public static final int textAppearanceSearchResultSubtitle = 16843424; // 0x10102a0
field public static final int textAppearanceSearchResultTitle = 16843425; // 0x10102a1
field public static final int textAppearanceSmall = 16842818; // 0x1010042
@@ -1309,9 +1313,9 @@
field public static final int thumbTint = 16843889; // 0x1010471
field public static final int thumbTintMode = 16843890; // 0x1010472
field public static final int thumbnail = 16843429; // 0x10102a5
- field public static final int tickMark = 16844044; // 0x101050c
- field public static final int tickMarkTint = 16844045; // 0x101050d
- field public static final int tickMarkTintMode = 16844046; // 0x101050e
+ field public static final int tickMark = 16844043; // 0x101050b
+ field public static final int tickMarkTint = 16844044; // 0x101050c
+ field public static final int tickMarkTintMode = 16844045; // 0x101050d
field public static final int tileMode = 16843265; // 0x1010201
field public static final int tileModeX = 16843895; // 0x1010477
field public static final int tileModeY = 16843896; // 0x1010478
@@ -1323,11 +1327,11 @@
field public static final int tintMode = 16843771; // 0x10103fb
field public static final int title = 16843233; // 0x10101e1
field public static final int titleCondensed = 16843234; // 0x10101e2
- field public static final int titleMargin = 16844026; // 0x10104fa
- field public static final int titleMarginBottom = 16844030; // 0x10104fe
- field public static final int titleMarginEnd = 16844028; // 0x10104fc
- field public static final int titleMarginStart = 16844027; // 0x10104fb
- field public static final int titleMarginTop = 16844029; // 0x10104fd
+ field public static final int titleMargin = 16844025; // 0x10104f9
+ field public static final int titleMarginBottom = 16844029; // 0x10104fd
+ field public static final int titleMarginEnd = 16844027; // 0x10104fb
+ field public static final int titleMarginStart = 16844026; // 0x10104fa
+ field public static final int titleMarginTop = 16844028; // 0x10104fc
field public static final int titleTextAppearance = 16843822; // 0x101042e
field public static final int titleTextColor = 16844003; // 0x10104e3
field public static final int titleTextStyle = 16843512; // 0x10102f8
@@ -1366,7 +1370,7 @@
field public static final int trimPathEnd = 16843785; // 0x1010409
field public static final int trimPathOffset = 16843786; // 0x101040a
field public static final int trimPathStart = 16843784; // 0x1010408
- field public static final int tunerCount = 16844063; // 0x101051f
+ field public static final int tunerCount = 16844062; // 0x101051e
field public static final int type = 16843169; // 0x10101a1
field public static final int typeface = 16842902; // 0x1010096
field public static final int uiOptions = 16843672; // 0x1010398
@@ -1374,7 +1378,7 @@
field public static final deprecated int unfocusedMonthDateColor = 16843588; // 0x1010344
field public static final int unselectedAlpha = 16843278; // 0x101020e
field public static final int updatePeriodMillis = 16843344; // 0x1010250
- field public static final int use32bitAbi = 16844055; // 0x1010517
+ field public static final int use32bitAbi = 16844054; // 0x1010516
field public static final int useDefaultMargins = 16843641; // 0x1010379
field public static final int useIntrinsicSizeAsMinimum = 16843536; // 0x1010310
field public static final int useLevel = 16843167; // 0x101019f
@@ -1386,7 +1390,7 @@
field public static final int valueType = 16843488; // 0x10102e0
field public static final int variablePadding = 16843157; // 0x1010195
field public static final int vendor = 16843751; // 0x10103e7
- field public static final int version = 16844059; // 0x101051b
+ field public static final int version = 16844058; // 0x101051a
field public static final int versionCode = 16843291; // 0x101021b
field public static final int versionName = 16843292; // 0x101021c
field public static final int verticalCorrection = 16843322; // 0x101023a
@@ -1430,7 +1434,7 @@
field public static final int windowAllowReturnTransitionOverlap = 16843835; // 0x101043b
field public static final int windowAnimationStyle = 16842926; // 0x10100ae
field public static final int windowBackground = 16842836; // 0x1010054
- field public static final int windowBackgroundFallback = 16844037; // 0x1010505
+ field public static final int windowBackgroundFallback = 16844036; // 0x1010504
field public static final int windowClipToOutline = 16843947; // 0x10104ab
field public static final int windowCloseOnTouchOutside = 16843611; // 0x101035b
field public static final int windowContentOverlay = 16842841; // 0x1010059
@@ -2481,6 +2485,7 @@
field public static final int Widget_Material_CompoundButton_CheckBox = 16974435; // 0x1030263
field public static final int Widget_Material_CompoundButton_RadioButton = 16974436; // 0x1030264
field public static final int Widget_Material_CompoundButton_Star = 16974437; // 0x1030265
+ field public static final int Widget_Material_CompoundButton_Switch = 16974554; // 0x10302da
field public static final int Widget_Material_DatePicker = 16974438; // 0x1030266
field public static final int Widget_Material_DropDownItem = 16974439; // 0x1030267
field public static final int Widget_Material_DropDownItem_Spinner = 16974440; // 0x1030268
@@ -2515,6 +2520,7 @@
field public static final int Widget_Material_Light_CompoundButton_CheckBox = 16974500; // 0x10302a4
field public static final int Widget_Material_Light_CompoundButton_RadioButton = 16974501; // 0x10302a5
field public static final int Widget_Material_Light_CompoundButton_Star = 16974502; // 0x10302a6
+ field public static final int Widget_Material_Light_CompoundButton_Switch = 16974555; // 0x10302db
field public static final int Widget_Material_Light_DatePicker = 16974503; // 0x10302a7
field public static final int Widget_Material_Light_DropDownItem = 16974504; // 0x10302a8
field public static final int Widget_Material_Light_DropDownItem_Spinner = 16974505; // 0x10302a9
@@ -3422,7 +3428,7 @@
method public boolean dispatchTouchEvent(android.view.MotionEvent);
method public boolean dispatchTrackballEvent(android.view.MotionEvent);
method public void dump(java.lang.String, java.io.FileDescriptor, java.io.PrintWriter, java.lang.String[]);
- method public void enterPictureInPicture();
+ method public void enterPictureInPictureMode();
method public android.view.View findViewById(int);
method public void finish();
method public void finishActivity(int);
@@ -3462,15 +3468,16 @@
method public android.view.Window getWindow();
method public android.view.WindowManager getWindowManager();
method public boolean hasWindowFocus();
- method public boolean inMultiWindow();
- method public boolean inPictureInPicture();
method public void invalidateOptionsMenu();
method public boolean isChangingConfigurations();
method public final boolean isChild();
method public boolean isDestroyed();
method public boolean isFinishing();
method public boolean isImmersive();
+ method public boolean isInMultiWindowMode();
+ method public boolean isInPictureInPictureMode();
method public boolean isLocalVoiceInteractionSupported();
+ method public boolean isOverlayWithDecorCaptionEnabled();
method public boolean isTaskRoot();
method public boolean isVoiceInteraction();
method public boolean isVoiceInteractionRoot();
@@ -3517,7 +3524,7 @@
method public void onLowMemory();
method public boolean onMenuItemSelected(int, android.view.MenuItem);
method public boolean onMenuOpened(int, android.view.Menu);
- method public void onMultiWindowChanged(boolean);
+ method public void onMultiWindowModeChanged(boolean);
method public boolean onNavigateUp();
method public boolean onNavigateUpFromChild(android.app.Activity);
method protected void onNewIntent(android.content.Intent);
@@ -3525,7 +3532,7 @@
method public void onOptionsMenuClosed(android.view.Menu);
method public void onPanelClosed(int, android.view.Menu);
method protected void onPause();
- method public void onPictureInPictureChanged(boolean);
+ method public void onPictureInPictureModeChanged(boolean);
method protected void onPostCreate(android.os.Bundle);
method public void onPostCreate(android.os.Bundle, android.os.PersistableBundle);
method protected void onPostResume();
@@ -3563,7 +3570,6 @@
method public android.view.ActionMode onWindowStartingActionMode(android.view.ActionMode.Callback, int);
method public void openContextMenu(android.view.View);
method public void openOptionsMenu();
- method public void overlayWithDecorCaption(boolean);
method public void overridePendingTransition(int, int);
method public void postponeEnterTransition();
method public void recreate();
@@ -3592,6 +3598,7 @@
method public void setImmersive(boolean);
method public void setIntent(android.content.Intent);
method public final void setMediaController(android.media.session.MediaController);
+ method public void setOverlayWithDecorCaptionEnabled(boolean);
method public final deprecated void setProgress(int);
method public final deprecated void setProgressBarIndeterminate(boolean);
method public final deprecated void setProgressBarIndeterminateVisibility(boolean);
@@ -4434,11 +4441,11 @@
method public void onInflate(android.content.Context, android.util.AttributeSet, android.os.Bundle);
method public deprecated void onInflate(android.app.Activity, android.util.AttributeSet, android.os.Bundle);
method public void onLowMemory();
- method public void onMultiWindowChanged(boolean);
+ method public void onMultiWindowModeChanged(boolean);
method public boolean onOptionsItemSelected(android.view.MenuItem);
method public void onOptionsMenuClosed(android.view.Menu);
method public void onPause();
- method public void onPictureInPictureChanged(boolean);
+ method public void onPictureInPictureModeChanged(boolean);
method public void onPrepareOptionsMenu(android.view.Menu);
method public void onRequestPermissionsResult(int, java.lang.String[], int[]);
method public void onResume();
@@ -4519,11 +4526,11 @@
method public void dispatchDestroy();
method public void dispatchDestroyView();
method public void dispatchLowMemory();
- method public void dispatchMultiWindowChanged(boolean);
+ method public void dispatchMultiWindowModeChanged(boolean);
method public boolean dispatchOptionsItemSelected(android.view.MenuItem);
method public void dispatchOptionsMenuClosed(android.view.Menu);
method public void dispatchPause();
- method public void dispatchPictureInPictureChanged(boolean);
+ method public void dispatchPictureInPictureModeChanged(boolean);
method public boolean dispatchPrepareOptionsMenu(android.view.Menu);
method public void dispatchResume();
method public void dispatchStart();
@@ -5755,8 +5762,8 @@
field public static final java.lang.String COMMAND_SECONDARY_TAP = "android.wallpaper.secondaryTap";
field public static final java.lang.String COMMAND_TAP = "android.wallpaper.tap";
field public static final java.lang.String EXTRA_LIVE_WALLPAPER_COMPONENT = "android.service.wallpaper.extra.LIVE_WALLPAPER_COMPONENT";
- field public static final int FLAG_SET_LOCK = 2; // 0x2
- field public static final int FLAG_SET_SYSTEM = 1; // 0x1
+ field public static final int FLAG_LOCK = 2; // 0x2
+ field public static final int FLAG_SYSTEM = 1; // 0x1
field public static final java.lang.String WALLPAPER_PREVIEW_META_DATA = "android.wallpaper.preview";
}
@@ -5856,7 +5863,7 @@
method public boolean getCrossProfileContactsSearchDisabled(android.content.ComponentName);
method public java.util.List<java.lang.String> getCrossProfileWidgetProviders(android.content.ComponentName);
method public int getCurrentFailedPasswordAttempts();
- method public java.lang.String getDeviceOwnerLockScreenInfo();
+ method public java.lang.CharSequence getDeviceOwnerLockScreenInfo();
method public java.util.List<byte[]> getInstalledCaCerts(android.content.ComponentName);
method public int getKeyguardDisabledFeatures(android.content.ComponentName);
method public java.lang.String getLongSupportMessage(android.content.ComponentName);
@@ -5864,7 +5871,6 @@
method public long getMaximumTimeToLock(android.content.ComponentName);
method public int getOrganizationColor(android.content.ComponentName);
method public java.lang.String getOrganizationName(android.content.ComponentName);
- method public boolean getPackageSuspended(android.content.ComponentName, java.lang.String);
method public android.app.admin.DevicePolicyManager getParentProfileInstance(android.content.ComponentName);
method public long getPasswordExpiration(android.content.ComponentName);
method public long getPasswordExpirationTimeout(android.content.ComponentName);
@@ -5894,14 +5900,16 @@
method public boolean hasGrantedPolicy(android.content.ComponentName, int);
method public boolean installCaCert(android.content.ComponentName, byte[]);
method public boolean installKeyPair(android.content.ComponentName, java.security.PrivateKey, java.security.cert.Certificate, java.lang.String);
- method public boolean installKeyPair(android.content.ComponentName, java.security.PrivateKey, java.security.cert.Certificate, java.lang.String, boolean);
+ method public boolean installKeyPair(android.content.ComponentName, java.security.PrivateKey, java.security.cert.Certificate[], java.lang.String, boolean);
method public boolean isActivePasswordSufficient();
method public boolean isAdminActive(android.content.ComponentName);
method public boolean isApplicationHidden(android.content.ComponentName, java.lang.String);
method public boolean isCallerApplicationRestrictionsManagingPackage();
method public boolean isDeviceOwnerApp(java.lang.String);
method public boolean isLockTaskPermitted(java.lang.String);
+ method public boolean isManagedProfile(android.content.ComponentName);
method public boolean isMasterVolumeMuted(android.content.ComponentName);
+ method public boolean isPackageSuspended(android.content.ComponentName, java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
method public boolean isProfileOwnerApp(java.lang.String);
method public boolean isProvisioningAllowed(java.lang.String);
method public boolean isSecurityLoggingEnabled(android.content.ComponentName);
@@ -5927,7 +5935,7 @@
method public void setCertInstallerPackage(android.content.ComponentName, java.lang.String) throws java.lang.SecurityException;
method public void setCrossProfileCallerIdDisabled(android.content.ComponentName, boolean);
method public void setCrossProfileContactsSearchDisabled(android.content.ComponentName, boolean);
- method public boolean setDeviceOwnerLockScreenInfo(android.content.ComponentName, java.lang.String);
+ method public void setDeviceOwnerLockScreenInfo(android.content.ComponentName, java.lang.CharSequence);
method public void setGlobalSetting(android.content.ComponentName, java.lang.String, java.lang.String);
method public boolean setKeyguardDisabled(android.content.ComponentName, boolean);
method public void setKeyguardDisabledFeatures(android.content.ComponentName, int);
@@ -8227,8 +8235,6 @@
method public java.lang.String getPackageResourcePath();
method public android.content.res.Resources getResources();
method public android.content.SharedPreferences getSharedPreferences(java.lang.String, int);
- method public android.content.SharedPreferences getSharedPreferences(java.io.File, int);
- method public java.io.File getSharedPreferencesPath(java.lang.String);
method public java.lang.Object getSystemService(java.lang.String);
method public java.lang.String getSystemServiceName(java.lang.Class<?>);
method public android.content.res.Resources.Theme getTheme();
@@ -8524,8 +8530,9 @@
field public static final java.lang.String ACTION_LOCKED_BOOT_COMPLETED = "android.intent.action.LOCKED_BOOT_COMPLETED";
field public static final java.lang.String ACTION_MAIN = "android.intent.action.MAIN";
field public static final java.lang.String ACTION_MANAGED_PROFILE_ADDED = "android.intent.action.MANAGED_PROFILE_ADDED";
- field public static final java.lang.String ACTION_MANAGED_PROFILE_AVAILABILITY_CHANGED = "android.intent.action.MANAGED_PROFILE_AVAILABILITY_CHANGED";
+ field public static final java.lang.String ACTION_MANAGED_PROFILE_AVAILABLE = "android.intent.action.MANAGED_PROFILE_AVAILABLE";
field public static final java.lang.String ACTION_MANAGED_PROFILE_REMOVED = "android.intent.action.MANAGED_PROFILE_REMOVED";
+ field public static final java.lang.String ACTION_MANAGED_PROFILE_UNAVAILABLE = "android.intent.action.MANAGED_PROFILE_UNAVAILABLE";
field public static final java.lang.String ACTION_MANAGED_PROFILE_UNLOCKED = "android.intent.action.MANAGED_PROFILE_UNLOCKED";
field public static final java.lang.String ACTION_MANAGE_NETWORK_USAGE = "android.intent.action.MANAGE_NETWORK_USAGE";
field public static final java.lang.String ACTION_MANAGE_PACKAGE_STORAGE = "android.intent.action.MANAGE_PACKAGE_STORAGE";
@@ -9923,6 +9930,7 @@
field public static final int PROTECTION_FLAG_PRE23 = 128; // 0x80
field public static final int PROTECTION_FLAG_PREINSTALLED = 1024; // 0x400
field public static final int PROTECTION_FLAG_PRIVILEGED = 16; // 0x10
+ field public static final int PROTECTION_FLAG_SETUP = 2048; // 0x800
field public static final deprecated int PROTECTION_FLAG_SYSTEM = 16; // 0x10
field public static final int PROTECTION_FLAG_VERIFIER = 512; // 0x200
field public static final int PROTECTION_MASK_BASE = 15; // 0xf
@@ -10000,7 +10008,7 @@
field public java.lang.String permission;
}
- public class ShortcutInfo implements android.os.Parcelable {
+ public final class ShortcutInfo implements android.os.Parcelable {
method public int describeContents();
method public android.content.ComponentName getActivityComponent();
method public android.os.PersistableBundle getExtras();
@@ -10008,6 +10016,7 @@
method public android.content.Intent getIntent();
method public long getLastChangedTimestamp();
method public java.lang.String getPackageName();
+ method public java.lang.String getText();
method public java.lang.String getTitle();
method public int getWeight();
method public boolean hasIconFile();
@@ -10035,6 +10044,7 @@
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 android.content.pm.ShortcutInfo.Builder setIntent(android.content.Intent);
+ method public android.content.pm.ShortcutInfo.Builder setText(java.lang.String);
method public android.content.pm.ShortcutInfo.Builder setTitle(java.lang.String);
method public android.content.pm.ShortcutInfo.Builder setWeight(int);
}
@@ -13509,6 +13519,7 @@
public final class Sensor {
method public int getFifoMaxEventCount();
method public int getFifoReservedEventCount();
+ method public int getId();
method public int getMaxDelay();
method public float getMaximumRange();
method public int getMinDelay();
@@ -13518,9 +13529,10 @@
method public float getResolution();
method public java.lang.String getStringType();
method public int getType();
- method public java.util.UUID getUuid();
method public java.lang.String getVendor();
method public int getVersion();
+ method public boolean isAdditionalInfoSupported();
+ method public boolean isDynamicSensor();
method public boolean isWakeUpSensor();
field public static final int REPORTING_MODE_CONTINUOUS = 0; // 0x0
field public static final int REPORTING_MODE_ONE_SHOT = 2; // 0x2
@@ -13639,8 +13651,9 @@
method public static void getRotationMatrixFromVector(float[], float[]);
method public java.util.List<android.hardware.Sensor> getSensorList(int);
method public deprecated int getSensors();
- method public void registerDynamicSensorCallback(android.hardware.SensorManager.DynamicSensorConnectionCallback);
- method public void registerDynamicSensorCallback(android.hardware.SensorManager.DynamicSensorConnectionCallback, android.os.Handler);
+ method public boolean isDynamicSensorDiscoverySupported();
+ method public void registerDynamicSensorCallback(android.hardware.SensorManager.DynamicSensorCallback);
+ method public void registerDynamicSensorCallback(android.hardware.SensorManager.DynamicSensorCallback, android.os.Handler);
method public deprecated boolean registerListener(android.hardware.SensorListener, int);
method public deprecated boolean registerListener(android.hardware.SensorListener, int, int);
method public boolean registerListener(android.hardware.SensorEventListener, android.hardware.Sensor, int);
@@ -13649,7 +13662,7 @@
method public boolean registerListener(android.hardware.SensorEventListener, android.hardware.Sensor, int, int, android.os.Handler);
method public static boolean remapCoordinateSystem(float[], int, int, float[]);
method public boolean requestTriggerSensor(android.hardware.TriggerEventListener, android.hardware.Sensor);
- method public void unregisterDynamicSensorCallback(android.hardware.SensorManager.DynamicSensorConnectionCallback);
+ method public void unregisterDynamicSensorCallback(android.hardware.SensorManager.DynamicSensorCallback);
method public deprecated void unregisterListener(android.hardware.SensorListener);
method public deprecated void unregisterListener(android.hardware.SensorListener, int);
method public void unregisterListener(android.hardware.SensorEventListener, android.hardware.Sensor);
@@ -13714,8 +13727,8 @@
field public static final float STANDARD_GRAVITY = 9.80665f;
}
- public static abstract class SensorManager.DynamicSensorConnectionCallback {
- ctor public SensorManager.DynamicSensorConnectionCallback();
+ public static abstract class SensorManager.DynamicSensorCallback {
+ ctor public SensorManager.DynamicSensorCallback();
method public void onDynamicSensorConnected(android.hardware.Sensor);
method public void onDynamicSensorDisconnected(android.hardware.Sensor);
}
@@ -14840,7 +14853,6 @@
public static abstract interface UCharacter.BidiPairedBracketType {
field public static final int CLOSE = 2; // 0x2
- field public static final int COUNT = 3; // 0x3
field public static final int NONE = 0; // 0x0
field public static final int OPEN = 1; // 0x1
}
@@ -14849,7 +14861,6 @@
field public static final int CANONICAL = 1; // 0x1
field public static final int CIRCLE = 3; // 0x3
field public static final int COMPAT = 2; // 0x2
- field public static final int COUNT = 18; // 0x12
field public static final int FINAL = 4; // 0x4
field public static final int FONT = 5; // 0x5
field public static final int FRACTION = 6; // 0x6
@@ -14869,7 +14880,6 @@
public static abstract interface UCharacter.EastAsianWidth {
field public static final int AMBIGUOUS = 1; // 0x1
- field public static final int COUNT = 6; // 0x6
field public static final int FULLWIDTH = 3; // 0x3
field public static final int HALFWIDTH = 2; // 0x2
field public static final int NARROW = 4; // 0x4
@@ -14879,7 +14889,6 @@
public static abstract interface UCharacter.GraphemeClusterBreak {
field public static final int CONTROL = 1; // 0x1
- field public static final int COUNT = 13; // 0xd
field public static final int CR = 2; // 0x2
field public static final int EXTEND = 3; // 0x3
field public static final int L = 4; // 0x4
@@ -14895,7 +14904,6 @@
}
public static abstract interface UCharacter.HangulSyllableType {
- field public static final int COUNT = 6; // 0x6
field public static final int LEADING_JAMO = 1; // 0x1
field public static final int LVT_SYLLABLE = 5; // 0x5
field public static final int LV_SYLLABLE = 4; // 0x4
@@ -14911,7 +14919,6 @@
field public static final int BEH = 4; // 0x4
field public static final int BETH = 5; // 0x5
field public static final int BURUSHASKI_YEH_BARREE = 54; // 0x36
- field public static final int COUNT = 86; // 0x56
field public static final int DAL = 6; // 0x6
field public static final int DALATH_RISH = 7; // 0x7
field public static final int E = 8; // 0x8
@@ -14996,7 +15003,6 @@
}
public static abstract interface UCharacter.JoiningType {
- field public static final int COUNT = 6; // 0x6
field public static final int DUAL_JOINING = 2; // 0x2
field public static final int JOIN_CAUSING = 1; // 0x1
field public static final int LEFT_JOINING = 3; // 0x3
@@ -15019,7 +15025,6 @@
field public static final int COMPLEX_CONTEXT = 24; // 0x18
field public static final int CONDITIONAL_JAPANESE_STARTER = 37; // 0x25
field public static final int CONTINGENT_BREAK = 7; // 0x7
- field public static final int COUNT = 40; // 0x28
field public static final int EXCLAMATION = 11; // 0xb
field public static final int GLUE = 12; // 0xc
field public static final int H2 = 31; // 0x1f
@@ -15051,7 +15056,6 @@
}
public static abstract interface UCharacter.NumericType {
- field public static final int COUNT = 4; // 0x4
field public static final int DECIMAL = 1; // 0x1
field public static final int DIGIT = 2; // 0x2
field public static final int NONE = 0; // 0x0
@@ -15061,7 +15065,6 @@
public static abstract interface UCharacter.SentenceBreak {
field public static final int ATERM = 1; // 0x1
field public static final int CLOSE = 2; // 0x2
- field public static final int COUNT = 15; // 0xf
field public static final int CR = 11; // 0xb
field public static final int EXTEND = 12; // 0xc
field public static final int FORMAT = 3; // 0x3
@@ -15204,7 +15207,6 @@
field public static final android.icu.lang.UCharacter.UnicodeBlock COPTIC_EPACT_NUMBERS;
field public static final int COPTIC_EPACT_NUMBERS_ID = 223; // 0xdf
field public static final int COPTIC_ID = 132; // 0x84
- field public static final int COUNT = 263; // 0x107
field public static final android.icu.lang.UCharacter.UnicodeBlock COUNTING_ROD_NUMERALS;
field public static final int COUNTING_ROD_NUMERALS_ID = 154; // 0x9a
field public static final android.icu.lang.UCharacter.UnicodeBlock CUNEIFORM;
@@ -15618,7 +15620,6 @@
public static abstract interface UCharacter.WordBreak {
field public static final int ALETTER = 1; // 0x1
- field public static final int COUNT = 17; // 0x11
field public static final int CR = 8; // 0x8
field public static final int DOUBLE_QUOTE = 16; // 0x10
field public static final int EXTEND = 9; // 0x9
@@ -15649,7 +15650,6 @@
}
public static abstract interface UCharacterEnums.ECharacterCategory {
- field public static final byte CHAR_CATEGORY_COUNT = 30; // 0x1e
field public static final byte COMBINING_SPACING_MARK = 8; // 0x8
field public static final byte CONNECTOR_PUNCTUATION = 22; // 0x16
field public static final byte CONTROL = 15; // 0xf
@@ -15689,7 +15689,6 @@
field public static final int ARABIC_NUMBER = 5; // 0x5
field public static final int BLOCK_SEPARATOR = 7; // 0x7
field public static final int BOUNDARY_NEUTRAL = 18; // 0x12
- field public static final int CHAR_DIRECTION_COUNT = 23; // 0x17
field public static final int COMMON_NUMBER_SEPARATOR = 6; // 0x6
field public static final byte DIRECTIONALITY_ARABIC_NUMBER = 5; // 0x5
field public static final byte DIRECTIONALITY_BOUNDARY_NEUTRAL = 18; // 0x12
@@ -15742,7 +15741,6 @@
field public static final int BIDI_MIRRORING_GLYPH = 16385; // 0x4001
field public static final int BIDI_PAIRED_BRACKET = 16397; // 0x400d
field public static final int BIDI_PAIRED_BRACKET_TYPE = 4117; // 0x1015
- field public static final int BINARY_LIMIT = 57; // 0x39
field public static final int BINARY_START = 0; // 0x0
field public static final int BLOCK = 4097; // 0x1001
field public static final int CANONICAL_COMBINING_CLASS = 4098; // 0x1002
@@ -15761,7 +15759,6 @@
field public static final int DEFAULT_IGNORABLE_CODE_POINT = 5; // 0x5
field public static final int DEPRECATED = 6; // 0x6
field public static final int DIACRITIC = 7; // 0x7
- field public static final int DOUBLE_LIMIT = 12289; // 0x3001
field public static final int DOUBLE_START = 12288; // 0x3000
field public static final int EAST_ASIAN_WIDTH = 4100; // 0x1004
field public static final int EXTENDER = 8; // 0x8
@@ -15780,7 +15777,6 @@
field public static final int IDS_TRINARY_OPERATOR = 19; // 0x13
field public static final int ID_CONTINUE = 15; // 0xf
field public static final int ID_START = 16; // 0x10
- field public static final int INT_LIMIT = 4118; // 0x1016
field public static final int INT_START = 4096; // 0x1000
field public static final int JOINING_GROUP = 4102; // 0x1006
field public static final int JOINING_TYPE = 4103; // 0x1007
@@ -15790,7 +15786,6 @@
field public static final int LOGICAL_ORDER_EXCEPTION = 21; // 0x15
field public static final int LOWERCASE = 22; // 0x16
field public static final int LOWERCASE_MAPPING = 16388; // 0x4004
- field public static final int MASK_LIMIT = 8193; // 0x2001
field public static final int MASK_START = 8192; // 0x2000
field public static final int MATH = 23; // 0x17
field public static final int NAME = 16389; // 0x4005
@@ -15805,7 +15800,6 @@
field public static final int NONCHARACTER_CODE_POINT = 24; // 0x18
field public static final int NUMERIC_TYPE = 4105; // 0x1009
field public static final int NUMERIC_VALUE = 12288; // 0x3000
- field public static final int OTHER_PROPERTY_LIMIT = 28673; // 0x7001
field public static final int OTHER_PROPERTY_START = 28672; // 0x7000
field public static final int PATTERN_SYNTAX = 42; // 0x2a
field public static final int PATTERN_WHITE_SPACE = 43; // 0x2b
@@ -15825,7 +15819,6 @@
field public static final int SIMPLE_TITLECASE_MAPPING = 16392; // 0x4008
field public static final int SIMPLE_UPPERCASE_MAPPING = 16393; // 0x4009
field public static final int SOFT_DOTTED = 27; // 0x1b
- field public static final int STRING_LIMIT = 16398; // 0x400e
field public static final int STRING_START = 16384; // 0x4000
field public static final int S_TERM = 35; // 0x23
field public static final int TERMINAL_PUNCTUATION = 28; // 0x1c
@@ -15842,7 +15835,6 @@
}
public static abstract interface UProperty.NameChoice {
- field public static final int COUNT = 2; // 0x2
field public static final int LONG = 1; // 0x1
field public static final int SHORT = 0; // 0x0
}
@@ -15887,7 +15879,6 @@
field public static final int CHAM = 66; // 0x42
field public static final int CHEROKEE = 6; // 0x6
field public static final int CIRTH = 67; // 0x43
- field public static final int CODE_LIMIT = 167; // 0xa7
field public static final int COMMON = 0; // 0x0
field public static final int COPTIC = 7; // 0x7
field public static final int CUNEIFORM = 101; // 0x65
@@ -16282,7 +16273,6 @@
public final class CollationKey implements java.lang.Comparable {
ctor public CollationKey(java.lang.String, byte[]);
- ctor public CollationKey(java.lang.String, android.icu.text.RawCollationKey);
method public int compareTo(android.icu.text.CollationKey);
method public boolean equals(android.icu.text.CollationKey);
method public android.icu.text.CollationKey getBound(int, int);
@@ -16292,7 +16282,6 @@
}
public static final class CollationKey.BoundMode {
- field public static final int COUNT = 3; // 0x3
field public static final int LOWER = 0; // 0x0
field public static final int UPPER = 1; // 0x1
field public static final int UPPER_LONG = 2; // 0x2
@@ -16324,7 +16313,6 @@
method public static final java.lang.String[] getKeywordValuesForLocale(java.lang.String, android.icu.util.ULocale, boolean);
method public static final java.lang.String[] getKeywords();
method public int getMaxVariable();
- method public abstract android.icu.text.RawCollationKey getRawCollationKey(java.lang.String, android.icu.text.RawCollationKey);
method public int[] getReorderCodes();
method public int getStrength();
method public android.icu.text.UnicodeSet getTailoredSet();
@@ -16364,7 +16352,6 @@
field public static final int DEFAULT = -1; // 0xffffffff
field public static final int DIGIT = 4100; // 0x1004
field public static final int FIRST = 4096; // 0x1000
- field public static final int LIMIT = 4101; // 0x1005
field public static final int NONE = 103; // 0x67
field public static final int OTHERS = 103; // 0x67
field public static final int PUNCTUATION = 4097; // 0x1001
@@ -16477,7 +16464,6 @@
field public static final int DOW_LOCAL_FIELD = 19; // 0x13
field public static final int ERA_FIELD = 0; // 0x0
field public static final int EXTENDED_YEAR_FIELD = 20; // 0x14
- field public static final int FIELD_COUNT = 36; // 0x24
field public static final int FRACTIONAL_SECOND_FIELD = 8; // 0x8
field public static final int FULL = 0; // 0x0
field public static final java.lang.String GENERIC_TZ = "vvvv";
@@ -16721,7 +16707,6 @@
field public static final int MONTH = 3; // 0x3
field public static final int QUARTER = 2; // 0x2
field public static final int SECOND = 13; // 0xd
- field public static final int TYPE_LIMIT = 16; // 0x10
field public static final int WEEKDAY = 6; // 0x6
field public static final int WEEK_OF_MONTH = 5; // 0x5
field public static final int WEEK_OF_YEAR = 4; // 0x4
@@ -17352,14 +17337,6 @@
enum_constant public static final android.icu.text.PluralRules.PluralType ORDINAL;
}
- public final class RawCollationKey extends android.icu.util.ByteArrayWrapper {
- ctor public RawCollationKey();
- ctor public RawCollationKey(int);
- ctor public RawCollationKey(byte[]);
- ctor public RawCollationKey(byte[], int);
- method public int compareTo(android.icu.text.RawCollationKey);
- }
-
public final class RelativeDateTimeFormatter {
method public java.lang.String combineDateAndTime(java.lang.String, java.lang.String);
method public java.lang.String format(double, android.icu.text.RelativeDateTimeFormatter.Direction, android.icu.text.RelativeDateTimeFormatter.RelativeUnit);
@@ -17443,7 +17420,6 @@
method public android.icu.text.CollationKey getCollationKey(java.lang.String);
method public void getContractionsAndExpansions(android.icu.text.UnicodeSet, android.icu.text.UnicodeSet, boolean) throws java.lang.Exception;
method public boolean getNumericCollation();
- method public android.icu.text.RawCollationKey getRawCollationKey(java.lang.String, android.icu.text.RawCollationKey);
method public java.lang.String getRules();
method public java.lang.String getRules(boolean);
method public android.icu.util.VersionInfo getUCAVersion();
@@ -17938,19 +17914,6 @@
field public static final int BE = 0; // 0x0
}
- public class ByteArrayWrapper implements java.lang.Comparable {
- ctor public ByteArrayWrapper();
- ctor public ByteArrayWrapper(byte[], int);
- ctor public ByteArrayWrapper(java.nio.ByteBuffer);
- method public final android.icu.util.ByteArrayWrapper append(byte[], int, int);
- method public int compareTo(android.icu.util.ByteArrayWrapper);
- method public android.icu.util.ByteArrayWrapper ensureCapacity(int);
- method public final byte[] releaseBytes();
- method public final android.icu.util.ByteArrayWrapper set(byte[], int, int);
- field public byte[] bytes;
- field public int size;
- }
-
abstract class CECalendar extends android.icu.util.Calendar {
ctor protected CECalendar();
ctor protected CECalendar(android.icu.util.TimeZone);
@@ -19308,10 +19271,19 @@
field public static final int MULTIPATH_INDICATOR_DETECTED = 1; // 0x1
field public static final int MULTIPATH_INDICATOR_NOT_USED = 2; // 0x2
field public static final int MULTIPATH_INDICATOR_UNKNOWN = 0; // 0x0
+ field public static final int STATE_BDS_D2_BIT_SYNC = 256; // 0x100
+ field public static final int STATE_BDS_D2_SUBFRAME_SYNC = 512; // 0x200
field public static final int STATE_BIT_SYNC = 2; // 0x2
field public static final int STATE_CODE_LOCK = 1; // 0x1
+ field public static final int STATE_GAL_E1BC_CODE_LOCK = 1024; // 0x400
+ field public static final int STATE_GAL_E1B_PAGE_SYNC = 4096; // 0x1000
+ field public static final int STATE_GAL_E1C_2ND_CODE_LOCK = 2048; // 0x800
+ field public static final int STATE_GLO_STRING_SYNC = 64; // 0x40
+ field public static final int STATE_GLO_TOD_DECODED = 128; // 0x80
field public static final int STATE_MSEC_AMBIGUOUS = 16; // 0x10
+ field public static final int STATE_SBAS_SYNC = 8192; // 0x2000
field public static final int STATE_SUBFRAME_SYNC = 4; // 0x4
+ field public static final int STATE_SYMBOL_SYNC = 32; // 0x20
field public static final int STATE_TOW_DECODED = 8; // 0x8
field public static final int STATE_UNKNOWN = 0; // 0x0
}
@@ -19908,7 +19880,7 @@
public static abstract class AudioManager.AudioRecordingCallback {
ctor public AudioManager.AudioRecordingCallback();
- method public void onRecordConfigChanged(android.media.AudioRecordingConfiguration[]);
+ method public void onRecordingConfigChanged(android.media.AudioRecordingConfiguration[]);
}
public static abstract interface AudioManager.OnAudioFocusChangeListener {
@@ -20185,6 +20157,7 @@
method public int getAttributeInt(java.lang.String, int);
method public boolean getLatLong(float[]);
method public byte[] getThumbnail();
+ method public long[] getThumbnailRange();
method public boolean hasThumbnail();
method public void saveAttributes() throws java.io.IOException;
method public void setAttribute(java.lang.String, java.lang.String);
@@ -20197,7 +20170,7 @@
field public static final int ORIENTATION_TRANSPOSE = 5; // 0x5
field public static final int ORIENTATION_TRANSVERSE = 7; // 0x7
field public static final int ORIENTATION_UNDEFINED = 0; // 0x0
- field public static final java.lang.String TAG_APERTURE = "FNumber";
+ field public static final deprecated java.lang.String TAG_APERTURE = "FNumber";
field public static final java.lang.String TAG_APERTURE_VALUE = "ApertureValue";
field public static final java.lang.String TAG_ARTIST = "Artist";
field public static final java.lang.String TAG_BITS_PER_SAMPLE = "BitsPerSample";
@@ -20268,7 +20241,7 @@
field public static final java.lang.String TAG_IMAGE_UNIQUE_ID = "ImageUniqueID";
field public static final java.lang.String TAG_IMAGE_WIDTH = "ImageWidth";
field public static final java.lang.String TAG_INTEROPERABILITY_INDEX = "InteroperabilityIndex";
- field public static final java.lang.String TAG_ISO = "ISOSpeedRatings";
+ field public static final deprecated java.lang.String TAG_ISO = "ISOSpeedRatings";
field public static final java.lang.String TAG_ISO_SPEED_RATINGS = "ISOSpeedRatings";
field public static final java.lang.String TAG_JPEG_INTERCHANGE_FORMAT = "JPEGInterchangeFormat";
field public static final java.lang.String TAG_JPEG_INTERCHANGE_FORMAT_LENGTH = "JPEGInterchangeFormatLength";
@@ -20676,12 +20649,13 @@
field public static final int DolbyVisionLevelUhd30 = 64; // 0x40
field public static final int DolbyVisionLevelUhd48 = 128; // 0x80
field public static final int DolbyVisionLevelUhd60 = 256; // 0x100
- field public static final int DolbyVisionProfileDvavDen = 2; // 0x2
- field public static final int DolbyVisionProfileDvavDer = 1; // 0x1
- field public static final int DolbyVisionProfileDvheDen = 4; // 0x4
- field public static final int DolbyVisionProfileDvheDer = 3; // 0x3
- field public static final int DolbyVisionProfileDvheDtr = 5; // 0x5
- field public static final int DolbyVisionProfileDvheStn = 6; // 0x6
+ field public static final int DolbyVisionProfileDvavPen = 2; // 0x2
+ field public static final int DolbyVisionProfileDvavPer = 1; // 0x1
+ field public static final int DolbyVisionProfileDvheDen = 8; // 0x8
+ field public static final int DolbyVisionProfileDvheDer = 4; // 0x4
+ field public static final int DolbyVisionProfileDvheDth = 64; // 0x40
+ field public static final int DolbyVisionProfileDvheDtr = 16; // 0x10
+ field public static final int DolbyVisionProfileDvheStn = 32; // 0x20
field public static final int H263Level10 = 1; // 0x1
field public static final int H263Level20 = 2; // 0x2
field public static final int H263Level30 = 4; // 0x4
@@ -28808,6 +28782,7 @@
field public static final int TEMPERATURE_CURRENT = 0; // 0x0
field public static final int TEMPERATURE_SHUTDOWN = 2; // 0x2
field public static final int TEMPERATURE_THROTTLING = 1; // 0x1
+ field public static final int TEMPERATURE_THROTTLING_BELOW_VR_MIN = 3; // 0x3
field public static final float UNDEFINED_TEMPERATURE = -3.4028235E38f;
}
@@ -29167,6 +29142,7 @@
method public boolean isInteractive();
method public boolean isPowerSaveMode();
method public deprecated boolean isScreenOn();
+ method public boolean isSustainedPerformanceModeSupported();
method public boolean isWakeLockLevelSupported(int);
method public android.os.PowerManager.WakeLock newWakeLock(int, java.lang.String);
method public void reboot(java.lang.String);
@@ -29180,6 +29156,7 @@
field public static final int RELEASE_FLAG_WAIT_FOR_NO_PROXIMITY = 1; // 0x1
field public static final deprecated int SCREEN_BRIGHT_WAKE_LOCK = 10; // 0xa
field public static final deprecated int SCREEN_DIM_WAKE_LOCK = 6; // 0x6
+ field public static final int SUSTAINED_PERFORMANCE_WAKE_LOCK = 256; // 0x100
}
public final class PowerManager.WakeLock {
@@ -29537,7 +29514,7 @@
method public android.os.health.HealthStats[] takeUidSnapshots(int[]);
}
- public class TimerStat implements android.os.Parcelable {
+ public final class TimerStat implements android.os.Parcelable {
ctor public TimerStat();
ctor public TimerStat(int, long);
ctor public TimerStat(android.os.Parcel);
@@ -29793,7 +29770,6 @@
method protected void onClick();
method protected android.view.View onCreateView(android.view.ViewGroup);
method public void onDependencyChanged(android.preference.Preference, boolean);
- method protected void onDetachedFromActivity();
method protected java.lang.Object onGetDefaultValue(android.content.res.TypedArray, int);
method public void onParentChanged(android.preference.Preference, boolean);
method protected void onPrepareForRemoval();
@@ -30427,7 +30403,7 @@
method public final boolean isDestroyed();
method public final boolean isPrinterDiscoveryStarted();
method public abstract void onDestroy();
- method public void onRequestCustomPrinterIcon(android.print.PrinterId, android.printservice.CustomPrinterIconCallback);
+ method public void onRequestCustomPrinterIcon(android.print.PrinterId, android.os.CancellationSignal, android.printservice.CustomPrinterIconCallback);
method public abstract void onStartPrinterDiscovery(java.util.List<android.print.PrinterId>);
method public abstract void onStartPrinterStateTracking(android.print.PrinterId);
method public abstract void onStopPrinterDiscovery();
@@ -30833,6 +30809,7 @@
field public static final int REJECTED_TYPE = 5; // 0x5
field public static final java.lang.String TRANSCRIPTION = "transcription";
field public static final java.lang.String TYPE = "type";
+ field public static final java.lang.String VIA_NUMBER = "via_number";
field public static final int VOICEMAIL_TYPE = 4; // 0x4
field public static final java.lang.String VOICEMAIL_URI = "voicemail_uri";
}
@@ -31983,6 +31960,7 @@
field public static final java.lang.String EXTRA_EXCLUDE_SELF = "android.provider.extra.EXCLUDE_SELF";
field public static final java.lang.String EXTRA_INFO = "info";
field public static final java.lang.String EXTRA_LOADING = "loading";
+ field public static final java.lang.String EXTRA_ORIENTATION = "android.provider.extra.ORIENTATION";
field public static final java.lang.String EXTRA_PROMPT = "android.provider.extra.PROMPT";
field public static final java.lang.String PROVIDER_INTERFACE = "android.content.action.DOCUMENTS_PROVIDER";
}
@@ -36827,6 +36805,7 @@
field public static final java.lang.String KEY_CARRIER_VT_AVAILABLE_BOOL = "carrier_vt_available_bool";
field public static final java.lang.String KEY_CARRIER_VVM_PACKAGE_NAME_STRING = "carrier_vvm_package_name_string";
field public static final java.lang.String KEY_CARRIER_WFC_IMS_AVAILABLE_BOOL = "carrier_wfc_ims_available_bool";
+ field public static final java.lang.String KEY_CARRIER_WFC_SUPPORTS_WIFI_ONLY_BOOL = "carrier_wfc_supports_wifi_only_bool";
field public static final java.lang.String KEY_CDMA_DTMF_TONE_DELAY_INT = "cdma_dtmf_tone_delay_int";
field public static final java.lang.String KEY_CDMA_NONROAMING_NETWORKS_STRING_ARRAY = "cdma_nonroaming_networks_string_array";
field public static final java.lang.String KEY_CDMA_ROAMING_NETWORKS_STRING_ARRAY = "cdma_roaming_networks_string_array";
@@ -37403,7 +37382,8 @@
method public java.lang.String getDeviceSoftwareVersion();
method public java.lang.String getGroupIdLevel1();
method public java.lang.String getGroupIdLevel1(int);
- method public java.lang.String getIccSimChallengeResponse(int, java.lang.String);
+ method public java.lang.String getIccAuthentication(int, int, java.lang.String);
+ method public java.lang.String getIccAuthentication(int, int, int, java.lang.String);
method public java.lang.String getLine1AlphaTag(int);
method public java.lang.String getLine1Number();
method public java.lang.String getLine1Number(int);
@@ -37472,6 +37452,13 @@
field public static final java.lang.String ACTION_CONFIGURE_VOICEMAIL = "android.telephony.action.CONFIGURE_VOICEMAIL";
field public static final java.lang.String ACTION_PHONE_STATE_CHANGED = "android.intent.action.PHONE_STATE";
field public static final java.lang.String ACTION_RESPOND_VIA_MESSAGE = "android.intent.action.RESPOND_VIA_MESSAGE";
+ field public static final int APPTYPE_CSIM = 4; // 0x4
+ field public static final int APPTYPE_ISIM = 5; // 0x5
+ field public static final int APPTYPE_RUIM = 3; // 0x3
+ field public static final int APPTYPE_SIM = 1; // 0x1
+ field public static final int APPTYPE_USIM = 2; // 0x2
+ field public static final int AUTHTYPE_EAP_AKA = 129; // 0x81
+ field public static final int AUTHTYPE_EAP_SIM = 128; // 0x80
field public static final int CALL_STATE_IDLE = 0; // 0x0
field public static final int CALL_STATE_OFFHOOK = 2; // 0x2
field public static final int CALL_STATE_RINGING = 1; // 0x1
@@ -38015,8 +38002,6 @@
method public java.lang.String getPackageResourcePath();
method public android.content.res.Resources getResources();
method public android.content.SharedPreferences getSharedPreferences(java.lang.String, int);
- method public android.content.SharedPreferences getSharedPreferences(java.io.File, int);
- method public java.io.File getSharedPreferencesPath(java.lang.String);
method public java.lang.Object getSystemService(java.lang.String);
method public java.lang.String getSystemServiceName(java.lang.Class<?>);
method public android.content.res.Resources.Theme getTheme();
@@ -42373,6 +42358,7 @@
method public boolean dispatchDragEvent(android.view.DragEvent);
method protected void dispatchDraw(android.graphics.Canvas);
method public void dispatchDrawableHotspotChanged(float, float);
+ method public void dispatchFinishTemporaryDetach();
method protected boolean dispatchGenericFocusedEvent(android.view.MotionEvent);
method public boolean dispatchGenericMotionEvent(android.view.MotionEvent);
method protected boolean dispatchGenericPointerEvent(android.view.MotionEvent);
@@ -42392,6 +42378,7 @@
method protected void dispatchSetActivated(boolean);
method protected void dispatchSetPressed(boolean);
method protected void dispatchSetSelected(boolean);
+ method public void dispatchStartTemporaryDetach();
method public void dispatchSystemUiVisibilityChanged(int);
method public boolean dispatchTouchEvent(android.view.MotionEvent);
method public boolean dispatchTrackballEvent(android.view.MotionEvent);
@@ -42409,6 +42396,7 @@
method public void findViewsWithText(java.util.ArrayList<android.view.View>, java.lang.CharSequence, int);
method protected deprecated boolean fitSystemWindows(android.graphics.Rect);
method public android.view.View focusSearch(int);
+ method public void forceHasOverlappingRendering(boolean);
method public void forceLayout();
method public static int generateViewId();
method public java.lang.CharSequence getAccessibilityClassName();
@@ -42454,6 +42442,7 @@
method public boolean getGlobalVisibleRect(android.graphics.Rect, android.graphics.Point);
method public final boolean getGlobalVisibleRect(android.graphics.Rect);
method public android.os.Handler getHandler();
+ method public final boolean getHasOverlappingRendering();
method public final int getHeight();
method public void getHitRect(android.graphics.Rect);
method public int getHorizontalFadingEdgeLength();
@@ -42602,6 +42591,7 @@
method public boolean isSelected();
method public boolean isShown();
method public boolean isSoundEffectsEnabled();
+ method public final boolean isTemporarilyDetached();
method public boolean isTextAlignmentResolved();
method public boolean isTextDirectionResolved();
method public boolean isVerticalFadingEdgeEnabled();
@@ -44358,6 +44348,7 @@
public final class AccessibilityWindowInfo implements android.os.Parcelable {
method public int describeContents();
+ method public android.view.accessibility.AccessibilityNodeInfo getAnchor();
method public void getBoundsInScreen(android.graphics.Rect);
method public android.view.accessibility.AccessibilityWindowInfo getChild(int);
method public int getChildCount();
@@ -44365,6 +44356,7 @@
method public int getLayer();
method public android.view.accessibility.AccessibilityWindowInfo getParent();
method public android.view.accessibility.AccessibilityNodeInfo getRoot();
+ method public java.lang.CharSequence getTitle();
method public int getType();
method public boolean isAccessibilityFocused();
method public boolean isActive();
@@ -44705,6 +44697,7 @@
ctor public BaseInputConnection(android.view.View, boolean);
method public boolean beginBatchEdit();
method public boolean clearMetaKeyStates(int);
+ method public void closeConnection();
method public boolean commitCompletion(android.view.inputmethod.CompletionInfo);
method public boolean commitCorrection(android.view.inputmethod.CorrectionInfo);
method public boolean commitText(java.lang.CharSequence, int);
@@ -44872,6 +44865,7 @@
public abstract interface InputConnection {
method public abstract boolean beginBatchEdit();
method public abstract boolean clearMetaKeyStates(int);
+ method public abstract void closeConnection();
method public abstract boolean commitCompletion(android.view.inputmethod.CompletionInfo);
method public abstract boolean commitCorrection(android.view.inputmethod.CorrectionInfo);
method public abstract boolean commitText(java.lang.CharSequence, int);
@@ -44904,6 +44898,7 @@
ctor public InputConnectionWrapper(android.view.inputmethod.InputConnection, boolean);
method public boolean beginBatchEdit();
method public boolean clearMetaKeyStates(int);
+ method public void closeConnection();
method public boolean commitCompletion(android.view.inputmethod.CompletionInfo);
method public boolean commitCorrection(android.view.inputmethod.CorrectionInfo);
method public boolean commitText(java.lang.CharSequence, int);
@@ -48351,14 +48346,21 @@
method public void collapseActionView();
method public void dismissPopupMenus();
method public int getContentInsetEnd();
+ method public int getContentInsetEndWithActions();
method public int getContentInsetLeft();
method public int getContentInsetRight();
method public int getContentInsetStart();
+ method public int getContentInsetStartWithNavigation();
+ method public int getCurrentContentInsetEnd();
+ method public int getCurrentContentInsetLeft();
+ method public int getCurrentContentInsetRight();
+ method public int getCurrentContentInsetStart();
method public android.graphics.drawable.Drawable getLogo();
method public java.lang.CharSequence getLogoDescription();
method public android.view.Menu getMenu();
method public java.lang.CharSequence getNavigationContentDescription();
method public android.graphics.drawable.Drawable getNavigationIcon();
+ method public android.view.View getNavigationView();
method public android.graphics.drawable.Drawable getOverflowIcon();
method public int getPopupTheme();
method public java.lang.CharSequence getSubtitle();
@@ -48372,6 +48374,8 @@
method public void inflateMenu(int);
method public boolean isOverflowMenuShowing();
method protected void onLayout(boolean, int, int, int, int);
+ method public void setContentInsetEndWithActions(int);
+ method public void setContentInsetStartWithNavigation(int);
method public void setContentInsetsAbsolute(int, int);
method public void setContentInsetsRelative(int, int);
method public void setLogo(int);
@@ -49356,9 +49360,7 @@
public final class FilePermission extends java.security.Permission implements java.io.Serializable {
ctor public FilePermission(java.lang.String, java.lang.String);
- method public boolean equals(java.lang.Object);
method public java.lang.String getActions();
- method public int hashCode();
method public boolean implies(java.security.Permission);
}
@@ -50097,6 +50099,7 @@
method public static int compare(boolean, boolean);
method public int compareTo(java.lang.Boolean);
method public static boolean getBoolean(java.lang.String);
+ method public static int hashCode(boolean);
method public static boolean parseBoolean(java.lang.String);
method public static java.lang.String toString(boolean);
method public static java.lang.Boolean valueOf(boolean);
@@ -50114,6 +50117,7 @@
method public static java.lang.Byte decode(java.lang.String) throws java.lang.NumberFormatException;
method public double doubleValue();
method public float floatValue();
+ method public static int hashCode(byte);
method public int intValue();
method public long longValue();
method public static byte parseByte(java.lang.String, int) throws java.lang.NumberFormatException;
@@ -50122,6 +50126,7 @@
method public static java.lang.Byte valueOf(byte);
method public static java.lang.Byte valueOf(java.lang.String, int) throws java.lang.NumberFormatException;
method public static java.lang.Byte valueOf(java.lang.String) throws java.lang.NumberFormatException;
+ field public static final int BYTES = 1; // 0x1
field public static final byte MAX_VALUE = 127; // 0x7f
field public static final byte MIN_VALUE = -128; // 0xffffff80
field public static final int SIZE = 8; // 0x8
@@ -50159,6 +50164,7 @@
method public static int getNumericValue(int);
method public static int getType(char);
method public static int getType(int);
+ method public static int hashCode(char);
method public static char highSurrogate(int);
method public static boolean isAlphabetic(int);
method public static boolean isBmpCodePoint(int);
@@ -50219,6 +50225,7 @@
method public static char toUpperCase(char);
method public static int toUpperCase(int);
method public static java.lang.Character valueOf(char);
+ field public static final int BYTES = 2; // 0x2
field public static final byte COMBINING_SPACING_MARK = 8; // 0x8
field public static final byte CONNECTOR_PUNCTUATION = 23; // 0x17
field public static final byte CONTROL = 15; // 0xf
@@ -50845,6 +50852,7 @@
method public static int floatToIntBits(float);
method public static int floatToRawIntBits(float);
method public float floatValue();
+ method public static int hashCode(float);
method public static float intBitsToFloat(int);
method public int intValue();
method public static boolean isFinite(float);
@@ -50853,11 +50861,15 @@
method public static boolean isNaN(float);
method public boolean isNaN();
method public long longValue();
+ method public static float max(float, float);
+ method public static float min(float, float);
method public static float parseFloat(java.lang.String) throws java.lang.NumberFormatException;
+ method public static float sum(float, float);
method public static java.lang.String toHexString(float);
method public static java.lang.String toString(float);
method public static java.lang.Float valueOf(java.lang.String) throws java.lang.NumberFormatException;
method public static java.lang.Float valueOf(float);
+ field public static final int BYTES = 4; // 0x4
field public static final int MAX_EXPONENT = 127; // 0x7f
field public static final float MAX_VALUE = 3.4028235E38f;
field public static final int MIN_EXPONENT = -126; // 0xffffff82
@@ -51037,6 +51049,7 @@
method public static java.lang.Long valueOf(java.lang.String, int) throws java.lang.NumberFormatException;
method public static java.lang.Long valueOf(java.lang.String) throws java.lang.NumberFormatException;
method public static java.lang.Long valueOf(long);
+ field public static final int BYTES = 8; // 0x8
field public static final long MAX_VALUE = 9223372036854775807L; // 0x7fffffffffffffffL
field public static final long MIN_VALUE = -9223372036854775808L; // 0x8000000000000000L
field public static final int SIZE = 64; // 0x40
@@ -51340,6 +51353,7 @@
method public static java.lang.Short decode(java.lang.String) throws java.lang.NumberFormatException;
method public double doubleValue();
method public float floatValue();
+ method public static int hashCode(short);
method public int intValue();
method public long longValue();
method public static short parseShort(java.lang.String, int) throws java.lang.NumberFormatException;
@@ -51349,6 +51363,7 @@
method public static java.lang.Short valueOf(java.lang.String, int) throws java.lang.NumberFormatException;
method public static java.lang.Short valueOf(java.lang.String) throws java.lang.NumberFormatException;
method public static java.lang.Short valueOf(short);
+ field public static final int BYTES = 2; // 0x2
field public static final short MAX_VALUE = 32767; // 0x7fff
field public static final short MIN_VALUE = -32768; // 0xffff8000
field public static final int SIZE = 16; // 0x10
@@ -52872,9 +52887,7 @@
public final class SocketPermission extends java.security.Permission implements java.io.Serializable {
ctor public SocketPermission(java.lang.String, java.lang.String);
- method public boolean equals(java.lang.Object);
method public java.lang.String getActions();
- method public int hashCode();
method public boolean implies(java.security.Permission);
}
@@ -53956,9 +53969,7 @@
public final class AllPermission extends java.security.Permission {
ctor public AllPermission();
ctor public AllPermission(java.lang.String, java.lang.String);
- method public boolean equals(java.lang.Object);
method public java.lang.String getActions();
- method public int hashCode();
method public boolean implies(java.security.Permission);
}
@@ -53972,9 +53983,7 @@
public abstract class BasicPermission extends java.security.Permission implements java.io.Serializable {
ctor public BasicPermission(java.lang.String);
ctor public BasicPermission(java.lang.String, java.lang.String);
- method public boolean equals(java.lang.Object);
method public java.lang.String getActions();
- method public int hashCode();
method public boolean implies(java.security.Permission);
}
@@ -54352,10 +54361,8 @@
public abstract class Permission implements java.security.Guard java.io.Serializable {
ctor public Permission(java.lang.String);
method public void checkGuard(java.lang.Object) throws java.lang.SecurityException;
- method public abstract boolean equals(java.lang.Object);
method public abstract java.lang.String getActions();
method public final java.lang.String getName();
- method public abstract int hashCode();
method public abstract boolean implies(java.security.Permission);
method public java.security.PermissionCollection newPermissionCollection();
}
@@ -54613,13 +54620,11 @@
public final class UnresolvedPermission extends java.security.Permission implements java.io.Serializable {
ctor public UnresolvedPermission(java.lang.String, java.lang.String, java.lang.String, java.security.cert.Certificate[]);
- method public boolean equals(java.lang.Object);
method public java.lang.String getActions();
method public java.lang.String getUnresolvedActions();
method public java.security.cert.Certificate[] getUnresolvedCerts();
method public java.lang.String getUnresolvedName();
method public java.lang.String getUnresolvedType();
- method public int hashCode();
method public boolean implies(java.security.Permission);
}
@@ -54677,8 +54682,6 @@
}
public abstract interface Permission {
- method public abstract boolean equals(java.lang.Object);
- method public abstract java.lang.String toString();
}
}
@@ -57394,6 +57397,7 @@
method public void forEach(java.util.function.Consumer<? super E>);
method public E get(int);
method public boolean removeIf(java.util.function.Predicate<? super E>);
+ method public void replaceAll(java.util.function.UnaryOperator<E>);
method public int size();
method public void sort(java.util.Comparator<? super E>);
method public java.util.Spliterator<E> spliterator();
@@ -57479,6 +57483,10 @@
method public static int hashCode(float[]);
method public static int hashCode(double[]);
method public static int hashCode(java.lang.Object[]);
+ method public static void parallelSetAll(T[], java.util.function.IntFunction<? extends T>);
+ method public static void parallelSetAll(int[], java.util.function.IntUnaryOperator);
+ method public static void parallelSetAll(long[], java.util.function.IntToLongFunction);
+ method public static void parallelSetAll(double[], java.util.function.IntToDoubleFunction);
method public static void parallelSort(byte[]);
method public static void parallelSort(byte[], int, int);
method public static void parallelSort(char[]);
@@ -58027,6 +58035,7 @@
method public java.lang.Object clone();
method public java.util.Set<java.util.Map.Entry<K, V>> entrySet();
method public void forEach(java.util.function.BiConsumer<? super K, ? super V>);
+ method public boolean replace(K, V, V);
}
public class HashSet extends java.util.AbstractSet implements java.lang.Cloneable java.io.Serializable java.util.Set {
@@ -58047,6 +58056,9 @@
ctor public Hashtable(java.util.Map<? extends K, ? extends V>);
method public synchronized void clear();
method public synchronized java.lang.Object clone();
+ method public synchronized V compute(K, java.util.function.BiFunction<? super K, ? super V, ? extends V>);
+ method public synchronized V computeIfAbsent(K, java.util.function.Function<? super K, ? extends V>);
+ method public synchronized V computeIfPresent(K, java.util.function.BiFunction<? super K, ? super V, ? extends V>);
method public synchronized boolean contains(java.lang.Object);
method public synchronized boolean containsKey(java.lang.Object);
method public boolean containsValue(java.lang.Object);
@@ -58054,13 +58066,19 @@
method public java.util.Set<java.util.Map.Entry<K, V>> entrySet();
method public synchronized void forEach(java.util.function.BiConsumer<? super K, ? super V>);
method public synchronized V get(java.lang.Object);
+ method public synchronized V getOrDefault(java.lang.Object, V);
method public synchronized boolean isEmpty();
method public java.util.Set<K> keySet();
method public synchronized java.util.Enumeration<K> keys();
+ method public synchronized V merge(K, V, java.util.function.BiFunction<? super V, ? super V, ? extends V>);
method public synchronized V put(K, V);
method public synchronized void putAll(java.util.Map<? extends K, ? extends V>);
+ method public synchronized V putIfAbsent(K, V);
method protected void rehash();
method public synchronized V remove(java.lang.Object);
+ method public synchronized boolean remove(java.lang.Object, java.lang.Object);
+ method public synchronized boolean replace(K, V, V);
+ method public synchronized V replace(K, V);
method public synchronized int size();
method public java.util.Collection<V> values();
}
@@ -58205,9 +58223,11 @@
method public abstract boolean remove(java.lang.Object);
method public abstract E remove(int);
method public abstract boolean removeAll(java.util.Collection<?>);
+ method public default void replaceAll(java.util.function.UnaryOperator<E>);
method public abstract boolean retainAll(java.util.Collection<?>);
method public abstract E set(int, E);
method public abstract int size();
+ method public default void sort(java.util.Comparator<? super E>);
method public abstract java.util.List<E> subList(int, int);
method public abstract java.lang.Object[] toArray();
method public abstract T[] toArray(T[]);
@@ -59122,9 +59142,11 @@
method public synchronized boolean removeElement(java.lang.Object);
method public synchronized void removeElementAt(int);
method public synchronized boolean removeIf(java.util.function.Predicate<? super E>);
+ method public synchronized void replaceAll(java.util.function.UnaryOperator<E>);
method public synchronized void setElementAt(E, int);
method public synchronized void setSize(int);
method public synchronized int size();
+ method public synchronized void sort(java.util.Comparator<? super E>);
method public java.util.Spliterator<E> spliterator();
method public synchronized void trimToSize();
field protected int capacityIncrement;
@@ -59590,6 +59612,7 @@
method public java.lang.Object clone();
method public boolean contains(java.lang.Object);
method public boolean containsAll(java.util.Collection<?>);
+ method public void forEach(java.util.function.Consumer<? super E>);
method public E get(int);
method public int indexOf(E, int);
method public int indexOf(java.lang.Object);
@@ -63967,11 +63990,9 @@
public final class PrivateCredentialPermission extends java.security.Permission {
ctor public PrivateCredentialPermission(java.lang.String, java.lang.String);
- method public boolean equals(java.lang.Object);
method public java.lang.String getActions();
method public java.lang.String getCredentialClass();
method public java.lang.String[][] getPrincipals();
- method public int hashCode();
method public boolean implies(java.security.Permission);
}
diff --git a/api/test-removed.txt b/api/test-removed.txt
index 86085c8..3f16bca 100644
--- a/api/test-removed.txt
+++ b/api/test-removed.txt
@@ -94,6 +94,10 @@
package android.media.tv {
+ public final class TvInputManager {
+ method public android.media.tv.TvInputManager.Hardware acquireTvInputHardware(int, android.media.tv.TvInputManager.HardwareCallback, android.media.tv.TvInputInfo);
+ }
+
public class TvView extends android.view.ViewGroup {
method public void requestUnblockContent(android.media.tv.TvContentRating);
}
diff --git a/cmds/pm/src/com/android/commands/pm/Pm.java b/cmds/pm/src/com/android/commands/pm/Pm.java
index 4025553..d44a1df 100644
--- a/cmds/pm/src/com/android/commands/pm/Pm.java
+++ b/cmds/pm/src/com/android/commands/pm/Pm.java
@@ -930,7 +930,7 @@
// In non-split user mode, userId can only be SYSTEM
int parentUserId = userId >= 0 ? userId : UserHandle.USER_SYSTEM;
info = mUm.createRestrictedProfile(name, parentUserId);
- mAm.addSharedAccountsFromParentUser(userId, parentUserId);
+ mAm.addSharedAccountsFromParentUser(parentUserId, userId);
} else if (userId < 0) {
info = mUm.createUser(name, flags);
} else {
diff --git a/cmds/sm/src/com/android/commands/sm/Sm.java b/cmds/sm/src/com/android/commands/sm/Sm.java
index b208e43..0e674c8 100644
--- a/cmds/sm/src/com/android/commands/sm/Sm.java
+++ b/cmds/sm/src/com/android/commands/sm/Sm.java
@@ -88,6 +88,8 @@
runForget();
} else if ("set-emulate-fbe".equals(op)) {
runSetEmulateFbe();
+ } else if ("get-fbe-mode".equals(op)) {
+ runGetFbeMode();
} else {
throw new IllegalArgumentException();
}
@@ -145,6 +147,16 @@
StorageManager.DEBUG_EMULATE_FBE);
}
+ public void runGetFbeMode() {
+ if (StorageManager.isFileEncryptedNativeOnly()) {
+ System.out.println("native");
+ } else if (StorageManager.isFileEncryptedEmulatedOnly()) {
+ System.out.println("emulated");
+ } else {
+ System.out.println("none");
+ }
+ }
+
public void runPartition() throws RemoteException {
final String diskId = nextArg();
final String type = nextArg();
diff --git a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
index 4019a56..ee03280 100644
--- a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
+++ b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
@@ -36,11 +36,11 @@
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityNodeInfo;
+import com.android.internal.R;
+
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
-import com.android.internal.R;
-
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
@@ -319,6 +319,9 @@
*/
public static final int FLAG_RETRIEVE_INTERACTIVE_WINDOWS = 0x00000040;
+ /** {@hide} */
+ public static final int FLAG_FORCE_DIRECT_BOOT_AWARE = 0x00010000;
+
/**
* The event types an {@link AccessibilityService} is interested in.
* <p>
@@ -687,8 +690,9 @@
}
/** {@hide} */
- public boolean isEncryptionAware() {
- return mResolveInfo.serviceInfo.directBootAware;
+ public boolean isDirectBootAware() {
+ return ((flags & FLAG_FORCE_DIRECT_BOOT_AWARE) != 0)
+ || mResolveInfo.serviceInfo.directBootAware;
}
/**
diff --git a/core/java/android/accessibilityservice/GestureDescription.java b/core/java/android/accessibilityservice/GestureDescription.java
index 7a0c89b..e18a34d 100644
--- a/core/java/android/accessibilityservice/GestureDescription.java
+++ b/core/java/android/accessibilityservice/GestureDescription.java
@@ -36,8 +36,7 @@
* Accessibility services with the
* {@link android.R.styleable#AccessibilityService_canPerformGestures} property can dispatch
* gestures. This class describes those gestures. Gestures are made up of one or more strokes.
- * Gestures are immutable; use the {@code create} methods to get common gesture, or a
- * {@code Builder} to create a new one.
+ * Gestures are immutable once built.
* <p>
* Spatial dimensions throughout are in screen pixels. Time is measured in milliseconds.
*/
diff --git a/core/java/android/accounts/AccountManager.java b/core/java/android/accounts/AccountManager.java
index e520b40..7465ed9 100644
--- a/core/java/android/accounts/AccountManager.java
+++ b/core/java/android/accounts/AccountManager.java
@@ -2798,6 +2798,15 @@
if (account == null) {
throw new IllegalArgumentException("account is null");
}
+
+ // Always include the calling package name. This just makes life easier
+ // down stream.
+ final Bundle optionsIn = new Bundle();
+ if (options != null) {
+ optionsIn.putAll(options);
+ }
+ optionsIn.putString(KEY_ANDROID_PACKAGE_NAME, mContext.getPackageName());
+
return new AmsTask(activity, handler, callback) {
@Override
public void doWork() throws RemoteException {
@@ -2806,7 +2815,7 @@
account,
authTokenType,
activity != null,
- options);
+ optionsIn);
}
}.start();
}
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index ee17e8a..0410a6e 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -51,12 +51,7 @@
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
-import android.graphics.Paint;
-import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
-import android.graphics.drawable.InsetDrawable;
-import android.graphics.drawable.LayerDrawable;
-import android.graphics.drawable.ShapeDrawable;
import android.hardware.input.InputManager;
import android.media.AudioManager;
import android.media.session.MediaController;
@@ -121,7 +116,6 @@
import com.android.internal.app.IVoiceInteractor;
import com.android.internal.app.ToolbarActionBar;
import com.android.internal.app.WindowDecorActionBar;
-import com.android.internal.policy.DecorView;
import com.android.internal.policy.PhoneWindow;
import java.io.FileDescriptor;
@@ -1249,7 +1243,7 @@
protected void onResume() {
if (DEBUG_LIFECYCLE) Slog.v(TAG, "onResume " + this);
getApplication().dispatchActivityResumed(this);
- mActivityTransitionState.onResume();
+ mActivityTransitionState.onResume(this, isTopOfTask());
mCalled = true;
}
@@ -1855,15 +1849,15 @@
* visa-versa.
* @see android.R.attr#resizeableActivity
*
- * @param inMultiWindow True if the activity is in multi-window mode.
+ * @param isInMultiWindowMode True if the activity is in multi-window mode.
*/
@CallSuper
- public void onMultiWindowChanged(boolean inMultiWindow) {
+ public void onMultiWindowModeChanged(boolean isInMultiWindowMode) {
if (DEBUG_LIFECYCLE) Slog.v(TAG,
- "onMultiWindowChanged " + this + ": " + inMultiWindow);
- mFragments.dispatchMultiWindowChanged(inMultiWindow);
+ "onMultiWindowModeChanged " + this + ": " + isInMultiWindowMode);
+ mFragments.dispatchMultiWindowModeChanged(isInMultiWindowMode);
if (mWindow != null) {
- mWindow.onMultiWindowChanged();
+ mWindow.onMultiWindowModeChanged();
}
}
@@ -1873,9 +1867,9 @@
*
* @return True if the activity is in multi-window mode.
*/
- public boolean inMultiWindow() {
+ public boolean isInMultiWindowMode() {
try {
- return ActivityManagerNative.getDefault().inMultiWindow(mToken);
+ return ActivityManagerNative.getDefault().isInMultiWindowMode(mToken);
} catch (RemoteException e) {
}
return false;
@@ -1885,13 +1879,13 @@
* Called by the system when the activity changes to and from picture-in-picture mode.
* @see android.R.attr#supportsPictureInPicture
*
- * @param inPictureInPicture True if the activity is in picture-in-picture mode.
+ * @param isInPictureInPictureMode True if the activity is in picture-in-picture mode.
*/
@CallSuper
- public void onPictureInPictureChanged(boolean inPictureInPicture) {
+ public void onPictureInPictureModeChanged(boolean isInPictureInPictureMode) {
if (DEBUG_LIFECYCLE) Slog.v(TAG,
- "onPictureInPictureChanged " + this + ": " + inPictureInPicture);
- mFragments.dispatchPictureInPictureChanged(inPictureInPicture);
+ "onPictureInPictureModeChanged " + this + ": " + isInPictureInPictureMode);
+ mFragments.dispatchPictureInPictureModeChanged(isInPictureInPictureMode);
}
/**
@@ -1900,9 +1894,9 @@
*
* @return True if the activity is in picture-in-picture mode.
*/
- public boolean inPictureInPicture() {
+ public boolean isInPictureInPictureMode() {
try {
- return ActivityManagerNative.getDefault().inPictureInPicture(mToken);
+ return ActivityManagerNative.getDefault().isInPictureInPictureMode(mToken);
} catch (RemoteException e) {
}
return false;
@@ -1912,9 +1906,9 @@
* Puts the activity in picture-in-picture mode.
* @see android.R.attr#supportsPictureInPicture
*/
- public void enterPictureInPicture() {
+ public void enterPictureInPictureMode() {
try {
- ActivityManagerNative.getDefault().enterPictureInPicture(mToken);
+ ActivityManagerNative.getDefault().enterPictureInPictureMode(mToken);
} catch (RemoteException e) {
}
}
@@ -5920,6 +5914,9 @@
* @return true if this is the topmost, non-finishing activity in its task.
*/
private boolean isTopOfTask() {
+ if (mToken == null || mWindow == null || !mWindowAdded) {
+ return false;
+ }
try {
return ActivityManagerNative.getDefault().isTopOfTask(mToken);
} catch (RemoteException e) {
@@ -6912,14 +6909,25 @@
}
/**
+ * Check whether the caption on freeform windows is displayed directly on the content.
+ *
+ * @return True if caption is displayed on content, false if it pushes the content down.
+ *
+ * @see {@link #setOverlayWithDecorCaptionEnabled(boolean)}
+ */
+ public boolean isOverlayWithDecorCaptionEnabled() {
+ return mWindow.isOverlayWithDecorCaptionEnabled();
+ }
+
+ /**
* Set whether the caption should displayed directly on the content rather than push it down.
*
* This affects only freeform windows since they display the caption and only the main
* window of the activity. The caption is used to drag the window around and also shows
* maximize and close action buttons.
*/
- public void overlayWithDecorCaption(boolean overlay) {
- mWindow.setOverlayDecorCaption(overlay);
+ public void setOverlayWithDecorCaptionEnabled(boolean enabled) {
+ mWindow.setOverlayWithDecorCaptionEnabled(enabled);
}
/**
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 6380801..d1f5143 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -31,7 +31,7 @@
import android.os.ParcelFileDescriptor;
import android.util.Log;
-import com.android.internal.app.ProcessStats;
+import com.android.internal.app.procstats.ProcessStats;
import com.android.internal.os.TransferPipe;
import com.android.internal.util.FastPrintWriter;
@@ -377,6 +377,12 @@
/** @hide Process is being cached for later use and is empty. */
public static final int PROCESS_STATE_CACHED_EMPTY = 16;
+ /** @hide The lowest process state number */
+ public static final int MIN_PROCESS_STATE = PROCESS_STATE_NONEXISTENT;
+
+ /** @hide The highest process state number */
+ public static final int MAX_PROCESS_STATE = PROCESS_STATE_CACHED_EMPTY;
+
/** @hide Should this process state be considered a background state? */
public static final boolean isProcStateBackground(int procState) {
return procState >= PROCESS_STATE_BACKUP;
@@ -1410,10 +1416,10 @@
public static final int RECENT_IGNORE_HOME_STACK_TASKS = 0x0008;
/**
- * Ignores all tasks that are on the docked stack.
+ * Ignores the top task in the docked stack.
* @hide
*/
- public static final int RECENT_INGORE_DOCKED_STACK_TASKS = 0x0010;
+ public static final int RECENT_INGORE_DOCKED_STACK_TOP_TASK = 0x0010;
/**
* Ignores all tasks that are on the pinned stack.
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index 4bf48a3..65d48e6 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -95,7 +95,7 @@
}
return sSystemReady;
}
- static boolean sSystemReady = false;
+ static volatile boolean sSystemReady = false;
static public void broadcastStickyIntent(Intent intent, String permission, int userId) {
broadcastStickyIntent(intent, permission, AppOpsManager.OP_NONE, userId);
@@ -2890,7 +2890,7 @@
case IN_MULTI_WINDOW_TRANSACTION: {
data.enforceInterface(IActivityManager.descriptor);
final IBinder token = data.readStrongBinder();
- final boolean inMultiWindow = inMultiWindow(token);
+ final boolean inMultiWindow = isInMultiWindowMode(token);
reply.writeNoException();
reply.writeInt(inMultiWindow ? 1 : 0);
return true;
@@ -2898,7 +2898,7 @@
case IN_PICTURE_IN_PICTURE_TRANSACTION: {
data.enforceInterface(IActivityManager.descriptor);
final IBinder token = data.readStrongBinder();
- final boolean inPip = inPictureInPicture(token);
+ final boolean inPip = isInPictureInPictureMode(token);
reply.writeNoException();
reply.writeInt(inPip ? 1 : 0);
return true;
@@ -2906,7 +2906,7 @@
case ENTER_PICTURE_IN_PICTURE_TRANSACTION: {
data.enforceInterface(IActivityManager.descriptor);
final IBinder token = data.readStrongBinder();
- enterPictureInPicture(token);
+ enterPictureInPictureMode(token);
reply.writeNoException();
return true;
}
@@ -6837,7 +6837,7 @@
}
@Override
- public boolean inMultiWindow(IBinder token) throws RemoteException {
+ public boolean isInMultiWindowMode(IBinder token) throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IActivityManager.descriptor);
@@ -6851,7 +6851,7 @@
}
@Override
- public boolean inPictureInPicture(IBinder token) throws RemoteException {
+ public boolean isInPictureInPictureMode(IBinder token) throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IActivityManager.descriptor);
@@ -6865,7 +6865,7 @@
}
@Override
- public void enterPictureInPicture(IBinder token) throws RemoteException {
+ public void enterPictureInPictureMode(IBinder token) throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IActivityManager.descriptor);
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index dbc6c84..14c4fc6 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -91,6 +91,7 @@
import android.util.Slog;
import android.util.SparseIntArray;
import android.util.SuperNotCalledException;
+import android.view.ContextThemeWrapper;
import android.view.Display;
import android.view.ThreadedRenderer;
import android.view.View;
@@ -1284,15 +1285,15 @@
}
@Override
- public void scheduleMultiWindowChanged(IBinder token, boolean inMultiWindow)
+ public void scheduleMultiWindowModeChanged(IBinder token, boolean isInMultiWindowMode)
throws RemoteException {
- sendMessage(H.MULTI_WINDOW_CHANGED, token, inMultiWindow ? 1 : 0);
+ sendMessage(H.MULTI_WINDOW_MODE_CHANGED, token, isInMultiWindowMode ? 1 : 0);
}
@Override
- public void schedulePictureInPictureChanged(IBinder token, boolean inPip)
+ public void schedulePictureInPictureModeChanged(IBinder token, boolean isInPipMode)
throws RemoteException {
- sendMessage(H.PICTURE_IN_PICTURE_CHANGED, token, inPip ? 1 : 0);
+ sendMessage(H.PICTURE_IN_PICTURE_MODE_CHANGED, token, isInPipMode ? 1 : 0);
}
@Override
@@ -1364,8 +1365,8 @@
public static final int ENTER_ANIMATION_COMPLETE = 149;
public static final int START_BINDER_TRACKING = 150;
public static final int STOP_BINDER_TRACKING_AND_DUMP = 151;
- public static final int MULTI_WINDOW_CHANGED = 152;
- public static final int PICTURE_IN_PICTURE_CHANGED = 153;
+ public static final int MULTI_WINDOW_MODE_CHANGED = 152;
+ public static final int PICTURE_IN_PICTURE_MODE_CHANGED = 153;
public static final int LOCAL_VOICE_INTERACTION_STARTED = 154;
String codeToString(int code) {
@@ -1420,8 +1421,8 @@
case CANCEL_VISIBLE_BEHIND: return "CANCEL_VISIBLE_BEHIND";
case BACKGROUND_VISIBLE_BEHIND_CHANGED: return "BACKGROUND_VISIBLE_BEHIND_CHANGED";
case ENTER_ANIMATION_COMPLETE: return "ENTER_ANIMATION_COMPLETE";
- case MULTI_WINDOW_CHANGED: return "MULTI_WINDOW_CHANGED";
- case PICTURE_IN_PICTURE_CHANGED: return "PICTURE_IN_PICTURE_CHANGED";
+ case MULTI_WINDOW_MODE_CHANGED: return "MULTI_WINDOW_MODE_CHANGED";
+ case PICTURE_IN_PICTURE_MODE_CHANGED: return "PICTURE_IN_PICTURE_MODE_CHANGED";
case LOCAL_VOICE_INTERACTION_STARTED: return "LOCAL_VOICE_INTERACTION_STARTED";
}
}
@@ -1666,11 +1667,11 @@
case STOP_BINDER_TRACKING_AND_DUMP:
handleStopBinderTrackingAndDump((ParcelFileDescriptor) msg.obj);
break;
- case MULTI_WINDOW_CHANGED:
- handleMultiWindowChanged((IBinder) msg.obj, msg.arg1 == 1);
+ case MULTI_WINDOW_MODE_CHANGED:
+ handleMultiWindowModeChanged((IBinder) msg.obj, msg.arg1 == 1);
break;
- case PICTURE_IN_PICTURE_CHANGED:
- handlePictureInPictureChanged((IBinder) msg.obj, msg.arg1 == 1);
+ case PICTURE_IN_PICTURE_MODE_CHANGED:
+ handlePictureInPictureModeChanged((IBinder) msg.obj, msg.arg1 == 1);
break;
case LOCAL_VOICE_INTERACTION_STARTED:
handleLocalVoiceInteractionStarted((IBinder) ((SomeArgs) msg.obj).arg1,
@@ -2924,17 +2925,17 @@
}
}
- private void handleMultiWindowChanged(IBinder token, boolean inMultiWindow) {
+ private void handleMultiWindowModeChanged(IBinder token, boolean isInMultiWindowMode) {
final ActivityClientRecord r = mActivities.get(token);
if (r != null) {
- r.activity.onMultiWindowChanged(inMultiWindow);
+ r.activity.onMultiWindowModeChanged(isInMultiWindowMode);
}
}
- private void handlePictureInPictureChanged(IBinder token, boolean inPip) {
+ private void handlePictureInPictureModeChanged(IBinder token, boolean isInPipMode) {
final ActivityClientRecord r = mActivities.get(token);
if (r != null) {
- r.activity.onPictureInPictureChanged(inPip);
+ r.activity.onPictureInPictureModeChanged(isInPipMode);
}
}
@@ -4632,7 +4633,21 @@
}
if (reportToActivity) {
- cb.onConfigurationChanged(newConfig);
+ Configuration configToReport = newConfig;
+
+ if (cb instanceof ContextThemeWrapper) {
+ // ContextThemeWrappers may override the configuration for that context.
+ // We must check and apply any overrides defined.
+ ContextThemeWrapper contextThemeWrapper = (ContextThemeWrapper) cb;
+ final Configuration localOverrideConfig =
+ contextThemeWrapper.getOverrideConfiguration();
+ if (localOverrideConfig != null) {
+ configToReport = new Configuration(newConfig);
+ configToReport.updateFrom(localOverrideConfig);
+ }
+ }
+
+ cb.onConfigurationChanged(configToReport);
}
if (activity != null) {
@@ -5077,26 +5092,6 @@
*/
TimeZone.setDefault(null);
- synchronized (mResourcesManager) {
- /*
- * Initialize the default locales in this process for the reasons we set the time zone.
- *
- * We do this through ResourcesManager, since we need to do locale negotiation.
- */
- mResourcesManager.setDefaultLocalesLocked(data.config.getLocales());
-
- /*
- * Update the system configuration since its preloaded and might not
- * reflect configuration changes. The configuration object passed
- * in AppBindData can be safely assumed to be up to date
- */
- mResourcesManager.applyConfigurationToResourcesLocked(data.config, data.compatInfo);
- mCurDefaultDisplayDpi = data.config.densityDpi;
-
- // This calls mResourcesManager so keep it within the synchronized block.
- applyCompatConfiguration(mCurDefaultDisplayDpi);
- }
-
data.info = getPackageInfoNoCheck(data.appInfo, data.compatInfo);
/**
@@ -5221,6 +5216,26 @@
}
final ContextImpl appContext = ContextImpl.createAppContext(this, data.info);
+ synchronized (mResourcesManager) {
+ /*
+ * Initialize the default locales in this process for the reasons we set the time zone.
+ *
+ * We do this through ResourcesManager, since we need to do locale negotiation.
+ */
+ mResourcesManager.setDefaultLocalesLocked(data.config.getLocales());
+
+ /*
+ * Update the system configuration since its preloaded and might not
+ * reflect configuration changes. The configuration object passed
+ * in AppBindData can be safely assumed to be up to date
+ */
+ mResourcesManager.applyConfigurationToResourcesLocked(data.config, data.compatInfo);
+ mCurDefaultDisplayDpi = data.config.densityDpi;
+
+ // This calls mResourcesManager so keep it within the synchronized block.
+ applyCompatConfiguration(mCurDefaultDisplayDpi);
+ }
+
if (!Process.isIsolated() && !"android".equals(appContext.getPackageName())) {
// This cache location probably points at credential-encrypted
// storage which may not be accessible yet; assign it anyway instead
diff --git a/core/java/android/app/ActivityTransitionCoordinator.java b/core/java/android/app/ActivityTransitionCoordinator.java
index 198bfb0a..e589e7c 100644
--- a/core/java/android/app/ActivityTransitionCoordinator.java
+++ b/core/java/android/app/ActivityTransitionCoordinator.java
@@ -25,6 +25,7 @@
import android.os.ResultReceiver;
import android.transition.Transition;
import android.transition.TransitionSet;
+import android.transition.Visibility;
import android.util.ArrayMap;
import android.view.GhostView;
import android.view.View;
@@ -378,6 +379,7 @@
transition.setEpicenterCallback(mEpicenterCallback);
transition = setTargets(transition, includeTransitioningViews);
}
+ noLayoutSuppressionForVisibilityTransitions(transition);
return transition;
}
@@ -944,6 +946,24 @@
}
}
+ /**
+ * Blocks suppressLayout from Visibility transitions. It is ok to suppress the layout,
+ * but we don't want to force the layout when suppressLayout becomes false. This leads
+ * to visual glitches.
+ */
+ private static void noLayoutSuppressionForVisibilityTransitions(Transition transition) {
+ if (transition instanceof Visibility) {
+ final Visibility visibility = (Visibility) transition;
+ visibility.setSuppressLayout(false);
+ } else if (transition instanceof TransitionSet) {
+ final TransitionSet set = (TransitionSet) transition;
+ final int count = set.getTransitionCount();
+ for (int i = 0; i < count; i++) {
+ noLayoutSuppressionForVisibilityTransitions(set.getTransitionAt(i));
+ }
+ }
+ }
+
private static class FixedEpicenterCallback extends Transition.EpicenterCallback {
private Rect mEpicenter;
diff --git a/core/java/android/app/ActivityTransitionState.java b/core/java/android/app/ActivityTransitionState.java
index bf0bd79..4a1aff7 100644
--- a/core/java/android/app/ActivityTransitionState.java
+++ b/core/java/android/app/ActivityTransitionState.java
@@ -236,9 +236,24 @@
}
}
- public void onResume() {
- restoreExitedViews();
- restoreReenteringViews();
+ public void onResume(Activity activity, boolean isTopOfTask) {
+ // After orientation change, the onResume can come in before the top Activity has
+ // left, so if the Activity is not top, wait a second for the top Activity to exit.
+ if (isTopOfTask || mEnterTransitionCoordinator == null) {
+ restoreExitedViews();
+ restoreReenteringViews();
+ } else {
+ activity.mHandler.postDelayed(new Runnable() {
+ @Override
+ public void run() {
+ if (mEnterTransitionCoordinator == null ||
+ mEnterTransitionCoordinator.isWaitingForRemoteExit()) {
+ restoreExitedViews();
+ restoreReenteringViews();
+ }
+ }
+ }, 1000);
+ }
}
public void clear() {
diff --git a/core/java/android/app/AlarmManager.java b/core/java/android/app/AlarmManager.java
index cb2130c4..e4fff9d 100644
--- a/core/java/android/app/AlarmManager.java
+++ b/core/java/android/app/AlarmManager.java
@@ -905,10 +905,12 @@
ListenerWrapper wrapper = null;
synchronized (AlarmManager.class) {
- final WeakReference<ListenerWrapper> wrapperRef;
- wrapperRef = sWrappers.get(listener);
- if (wrapperRef != null) {
- wrapper = wrapperRef.get();
+ if (sWrappers != null) {
+ final WeakReference<ListenerWrapper> wrapperRef;
+ wrapperRef = sWrappers.get(listener);
+ if (wrapperRef != null) {
+ wrapper = wrapperRef.get();
+ }
}
}
diff --git a/core/java/android/app/ApplicationThreadNative.java b/core/java/android/app/ApplicationThreadNative.java
index 744ddf7..ea86dd0 100644
--- a/core/java/android/app/ApplicationThreadNative.java
+++ b/core/java/android/app/ApplicationThreadNative.java
@@ -736,7 +736,7 @@
data.enforceInterface(IApplicationThread.descriptor);
final IBinder b = data.readStrongBinder();
final boolean inMultiWindow = data.readInt() != 0;
- scheduleMultiWindowChanged(b, inMultiWindow);
+ scheduleMultiWindowModeChanged(b, inMultiWindow);
return true;
}
@@ -745,7 +745,7 @@
data.enforceInterface(IApplicationThread.descriptor);
final IBinder b = data.readStrongBinder();
final boolean inPip = data.readInt() != 0;
- schedulePictureInPictureChanged(b, inPip);
+ schedulePictureInPictureModeChanged(b, inPip);
return true;
}
@@ -1498,24 +1498,24 @@
}
@Override
- public final void scheduleMultiWindowChanged(
- IBinder token, boolean inMultiWindow) throws RemoteException {
+ public final void scheduleMultiWindowModeChanged(
+ IBinder token, boolean isInMultiWindowMode) throws RemoteException {
Parcel data = Parcel.obtain();
data.writeInterfaceToken(IApplicationThread.descriptor);
data.writeStrongBinder(token);
- data.writeInt(inMultiWindow ? 1 : 0);
+ data.writeInt(isInMultiWindowMode ? 1 : 0);
mRemote.transact(SCHEDULE_MULTI_WINDOW_CHANGED_TRANSACTION, data, null,
IBinder.FLAG_ONEWAY);
data.recycle();
}
@Override
- public final void schedulePictureInPictureChanged(IBinder token, boolean inPip)
+ public final void schedulePictureInPictureModeChanged(IBinder token, boolean isInPipMode)
throws RemoteException {
Parcel data = Parcel.obtain();
data.writeInterfaceToken(IApplicationThread.descriptor);
data.writeStrongBinder(token);
- data.writeInt(inPip ? 1 : 0);
+ data.writeInt(isInPipMode ? 1 : 0);
mRemote.transact(SCHEDULE_PICTURE_IN_PICTURE_CHANGED_TRANSACTION, data, null,
IBinder.FLAG_ONEWAY);
data.recycle();
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index d28f1fb..6bb853a 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -1993,7 +1993,7 @@
ContextImpl context = new ContextImpl(null, mainThread,
packageInfo, null, null, 0, null, null, Display.INVALID_DISPLAY);
context.mResources.updateConfiguration(context.mResourcesManager.getConfiguration(),
- context.mResourcesManager.getDisplayMetricsLocked());
+ context.mResourcesManager.getDisplayMetrics());
return context;
}
@@ -2065,16 +2065,34 @@
|| overrideConfiguration != null
|| (compatInfo != null && compatInfo.applicationScale
!= resources.getCompatibilityInfo().applicationScale)) {
- resources = mResourcesManager.getResources(
- activityToken,
- packageInfo.getResDir(),
- packageInfo.getSplitResDirs(),
- packageInfo.getOverlayDirs(),
- packageInfo.getApplicationInfo().sharedLibraryFiles,
- displayId,
- overrideConfiguration,
- compatInfo,
- packageInfo.getClassLoader());
+
+ if (container != null) {
+ // This is a nested Context, so it can't be a base Activity context.
+ // Just create a regular Resources object associated with the Activity.
+ resources = mResourcesManager.getResources(
+ activityToken,
+ packageInfo.getResDir(),
+ packageInfo.getSplitResDirs(),
+ packageInfo.getOverlayDirs(),
+ packageInfo.getApplicationInfo().sharedLibraryFiles,
+ displayId,
+ overrideConfiguration,
+ compatInfo,
+ packageInfo.getClassLoader());
+ } else {
+ // This is not a nested Context, so it must be the root Activity context.
+ // All other nested Contexts will inherit the configuration set here.
+ resources = mResourcesManager.createBaseActivityResources(
+ activityToken,
+ packageInfo.getResDir(),
+ packageInfo.getSplitResDirs(),
+ packageInfo.getOverlayDirs(),
+ packageInfo.getApplicationInfo().sharedLibraryFiles,
+ displayId,
+ overrideConfiguration,
+ compatInfo,
+ packageInfo.getClassLoader());
+ }
}
}
mResources = resources;
diff --git a/core/java/android/app/DatePickerDialog.java b/core/java/android/app/DatePickerDialog.java
index 83dc506..bd55a06 100644
--- a/core/java/android/app/DatePickerDialog.java
+++ b/core/java/android/app/DatePickerDialog.java
@@ -58,7 +58,7 @@
* @param context the parent context
*/
public DatePickerDialog(@NonNull Context context) {
- this(context, 0);
+ this(context, 0, null, Calendar.getInstance(), -1, -1, -1);
}
/**
@@ -70,24 +70,7 @@
* {@code context}'s default alert dialog theme
*/
public DatePickerDialog(@NonNull Context context, @StyleRes int themeResId) {
- super(context, resolveDialogTheme(context, themeResId));
-
- final Context themeContext = getContext();
- final LayoutInflater inflater = LayoutInflater.from(themeContext);
- final View view = inflater.inflate(R.layout.date_picker_dialog, null);
- setView(view);
-
- setButton(BUTTON_POSITIVE, themeContext.getString(R.string.ok), this);
- setButton(BUTTON_NEGATIVE, themeContext.getString(R.string.cancel), this);
- setButtonPanelLayoutHint(LAYOUT_HINT_SIDE);
-
- final Calendar calendar = Calendar.getInstance();
- final int year = calendar.get(Calendar.YEAR);
- final int monthOfYear = calendar.get(Calendar.MONTH);
- final int dayOfMonth = calendar.get(Calendar.DAY_OF_MONTH);
- mDatePicker = (DatePicker) view.findViewById(R.id.datePicker);
- mDatePicker.init(year, monthOfYear, dayOfMonth, this);
- mDatePicker.setValidationCallback(mValidationCallback);
+ this(context, themeResId, null, Calendar.getInstance(), -1, -1, -1);
}
/**
@@ -104,7 +87,7 @@
*/
public DatePickerDialog(@NonNull Context context, @Nullable OnDateSetListener listener,
int year, int month, int dayOfMonth) {
- this(context, 0, listener, year, month, dayOfMonth);
+ this(context, 0, listener, null, year, month, dayOfMonth);
}
/**
@@ -116,16 +99,40 @@
* {@code context}'s default alert dialog theme
* @param listener the listener to call when the user sets the date
* @param year the initially selected year
- * @param month the initially selected month (0-11 for compatibility with
- * {@link Calendar#MONTH})
+ * @param monthOfYear the initially selected month of the year (0-11 for
+ * compatibility with {@link Calendar#MONTH})
* @param dayOfMonth the initially selected day of month (1-31, depending
* on month)
*/
public DatePickerDialog(@NonNull Context context, @StyleRes int themeResId,
- @Nullable OnDateSetListener listener, int year, int month, int dayOfMonth) {
- this(context, themeResId);
+ @Nullable OnDateSetListener listener, int year, int monthOfYear, int dayOfMonth) {
+ this(context, themeResId, listener, null, year, monthOfYear, dayOfMonth);
+ }
- mDatePicker.updateDate(year, month, dayOfMonth);
+ private DatePickerDialog(@NonNull Context context, @StyleRes int themeResId,
+ @Nullable OnDateSetListener listener, @Nullable Calendar calendar, int year,
+ int monthOfYear, int dayOfMonth) {
+ super(context, resolveDialogTheme(context, themeResId));
+
+ final Context themeContext = getContext();
+ final LayoutInflater inflater = LayoutInflater.from(themeContext);
+ final View view = inflater.inflate(R.layout.date_picker_dialog, null);
+ setView(view);
+
+ setButton(BUTTON_POSITIVE, themeContext.getString(R.string.ok), this);
+ setButton(BUTTON_NEGATIVE, themeContext.getString(R.string.cancel), this);
+ setButtonPanelLayoutHint(LAYOUT_HINT_SIDE);
+
+ if (calendar != null) {
+ year = calendar.get(Calendar.YEAR);
+ monthOfYear = calendar.get(Calendar.MONTH);
+ dayOfMonth = calendar.get(Calendar.DAY_OF_MONTH);
+ }
+
+ mDatePicker = (DatePicker) view.findViewById(R.id.datePicker);
+ mDatePicker.init(year, monthOfYear, dayOfMonth, this);
+ mDatePicker.setValidationCallback(mValidationCallback);
+
mDateSetListener = listener;
}
diff --git a/core/java/android/app/Dialog.java b/core/java/android/app/Dialog.java
index 0bb1097..85a0403 100644
--- a/core/java/android/app/Dialog.java
+++ b/core/java/android/app/Dialog.java
@@ -16,6 +16,10 @@
package android.app;
+import com.android.internal.R;
+import com.android.internal.app.WindowDecorActionBar;
+import com.android.internal.policy.PhoneWindow;
+
import android.annotation.CallSuper;
import android.annotation.DrawableRes;
import android.annotation.IdRes;
@@ -43,7 +47,6 @@
import android.view.ContextThemeWrapper;
import android.view.Gravity;
import android.view.KeyEvent;
-import android.view.KeyboardShortcutGroup;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
@@ -57,12 +60,7 @@
import android.view.WindowManager;
import android.view.accessibility.AccessibilityEvent;
-import com.android.internal.R;
-import com.android.internal.app.WindowDecorActionBar;
-import com.android.internal.policy.PhoneWindow;
-
import java.lang.ref.WeakReference;
-import java.util.List;
/**
* Base class for Dialogs.
@@ -94,11 +92,14 @@
KeyEvent.Callback, OnCreateContextMenuListener, Window.OnWindowDismissedCallback {
private static final String TAG = "Dialog";
private Activity mOwnerActivity;
-
+
+ private final WindowManager mWindowManager;
+
final Context mContext;
- final WindowManager mWindowManager;
- Window mWindow;
+ final Window mWindow;
+
View mDecor;
+
private ActionBar mActionBar;
/**
* This field should be made private, so it is hidden from the SDK.
@@ -123,7 +124,7 @@
private static final int CANCEL = 0x44;
private static final int SHOW = 0x45;
- private Handler mListenersHandler;
+ private final Handler mListenersHandler;
private SearchEvent mSearchEvent;
@@ -131,11 +132,7 @@
private int mActionModeTypeStarting = ActionMode.TYPE_PRIMARY;
- private final Runnable mDismissAction = new Runnable() {
- public void run() {
- dismissDialog();
- }
- };
+ private final Runnable mDismissAction = this::dismissDialog;
/**
* Creates a dialog window that uses the default dialog theme.
@@ -198,14 +195,15 @@
* @hide
*/
@Deprecated
- protected Dialog(@NonNull Context context, boolean cancelable, Message cancelCallback) {
+ protected Dialog(@NonNull Context context, boolean cancelable,
+ @Nullable Message cancelCallback) {
this(context);
mCancelable = cancelable;
mCancelMessage = cancelCallback;
}
protected Dialog(@NonNull Context context, boolean cancelable,
- OnCancelListener cancelListener) {
+ @Nullable OnCancelListener cancelListener) {
this(context);
mCancelable = cancelable;
setOnCancelListener(cancelListener);
@@ -216,8 +214,7 @@
*
* @return Context The Context used by the Dialog.
*/
- @NonNull
- public final Context getContext() {
+ public final @NonNull Context getContext() {
return mContext;
}
@@ -226,7 +223,7 @@
*
* @return The ActionBar attached to the dialog or null if no ActionBar is present.
*/
- public ActionBar getActionBar() {
+ public @Nullable ActionBar getActionBar() {
return mActionBar;
}
@@ -236,7 +233,7 @@
*
* @param activity The Activity that owns this dialog.
*/
- public final void setOwnerActivity(Activity activity) {
+ public final void setOwnerActivity(@NonNull Activity activity) {
mOwnerActivity = activity;
getWindow().setVolumeControlStream(mOwnerActivity.getVolumeControlStream());
@@ -250,7 +247,7 @@
*
* @return The Activity that owns this Dialog.
*/
- public final Activity getOwnerActivity() {
+ public final @Nullable Activity getOwnerActivity() {
return mOwnerActivity;
}
@@ -316,13 +313,10 @@
l = nl;
}
- try {
- mWindowManager.addView(mDecor, l);
- mShowing = true;
-
- sendShowMessage();
- } finally {
- }
+ mWindowManager.addView(mDecor, l);
+ mShowing = true;
+
+ sendShowMessage();
}
/**
@@ -388,7 +382,7 @@
}
}
- // internal method to make sure mcreated is set properly without requiring
+ // internal method to make sure mCreated is set properly without requiring
// users to call through to super in onCreate
void dispatchOnCreate(Bundle savedInstanceState) {
if (!mCreated) {
@@ -400,7 +394,7 @@
/**
* Similar to {@link Activity#onCreate}, you should initialize your dialog
* in this method, including calling {@link #setContentView}.
- * @param savedInstanceState If this dialog is being reinitalized after a
+ * @param savedInstanceState If this dialog is being reinitialized after a
* the hosting activity was previously shut down, holds the result from
* the most recent call to {@link #onSaveInstanceState}, or null if this
* is the first time.
@@ -433,7 +427,7 @@
* state.
* @return A bundle with the state of the dialog.
*/
- public Bundle onSaveInstanceState() {
+ public @NonNull Bundle onSaveInstanceState() {
Bundle bundle = new Bundle();
bundle.putBoolean(DIALOG_SHOWING_TAG, mShowing);
if (mCreated) {
@@ -452,7 +446,7 @@
* @param savedInstanceState The state of the dialog previously saved by
* {@link #onSaveInstanceState()}.
*/
- public void onRestoreInstanceState(Bundle savedInstanceState) {
+ public void onRestoreInstanceState(@NonNull Bundle savedInstanceState) {
final Bundle dialogHierarchyState = savedInstanceState.getBundle(DIALOG_HIERARCHY_TAG);
if (dialogHierarchyState == null) {
// dialog has never been shown, or onCreated, nothing to restore.
@@ -473,7 +467,7 @@
* @return Window The current window, or null if the activity is not
* visual.
*/
- public Window getWindow() {
+ public @Nullable Window getWindow() {
return mWindow;
}
@@ -486,7 +480,7 @@
* @see #getWindow
* @see android.view.Window#getCurrentFocus
*/
- public View getCurrentFocus() {
+ public @Nullable View getCurrentFocus() {
return mWindow != null ? mWindow.getCurrentFocus() : null;
}
@@ -498,8 +492,7 @@
* @param id the identifier of the view to find
* @return The view with the given id or null.
*/
- @Nullable
- public View findViewById(@IdRes int id) {
+ public @Nullable View findViewById(@IdRes int id) {
return mWindow.findViewById(id);
}
@@ -520,19 +513,19 @@
*
* @param view The desired content to display.
*/
- public void setContentView(View view) {
+ public void setContentView(@NonNull View view) {
mWindow.setContentView(view);
}
/**
* Set the screen content to an explicit view. This view is placed
* directly into the screen's view hierarchy. It can itself be a complex
- * view hierarhcy.
+ * view hierarchy.
*
* @param view The desired content to display.
* @param params Layout parameters for the view.
*/
- public void setContentView(View view, ViewGroup.LayoutParams params) {
+ public void setContentView(@NonNull View view, @Nullable ViewGroup.LayoutParams params) {
mWindow.setContentView(view, params);
}
@@ -543,7 +536,7 @@
* @param view The desired content to display.
* @param params Layout parameters for the view.
*/
- public void addContentView(View view, ViewGroup.LayoutParams params) {
+ public void addContentView(@NonNull View view, @Nullable ViewGroup.LayoutParams params) {
mWindow.addContentView(view, params);
}
@@ -552,7 +545,7 @@
*
* @param title The new text to display in the title.
*/
- public void setTitle(CharSequence title) {
+ public void setTitle(@Nullable CharSequence title) {
mWindow.setTitle(title);
mWindow.getAttributes().setTitle(title);
}
@@ -578,7 +571,8 @@
* @see #onKeyUp
* @see android.view.KeyEvent
*/
- public boolean onKeyDown(int keyCode, KeyEvent event) {
+ @Override
+ public boolean onKeyDown(int keyCode, @NonNull KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
event.startTracking();
return true;
@@ -592,7 +586,8 @@
* KeyEvent.Callback.onKeyLongPress()}: always returns false (doesn't handle
* the event).
*/
- public boolean onKeyLongPress(int keyCode, KeyEvent event) {
+ @Override
+ public boolean onKeyLongPress(int keyCode, @NonNull KeyEvent event) {
return false;
}
@@ -605,7 +600,8 @@
* @see #onKeyDown
* @see KeyEvent
*/
- public boolean onKeyUp(int keyCode, KeyEvent event) {
+ @Override
+ public boolean onKeyUp(int keyCode, @NonNull KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK && event.isTracking()
&& !event.isCanceled()) {
onBackPressed();
@@ -619,7 +615,8 @@
* KeyEvent.Callback.onKeyMultiple()}: always returns false (doesn't handle
* the event).
*/
- public boolean onKeyMultiple(int keyCode, int repeatCount, KeyEvent event) {
+ @Override
+ public boolean onKeyMultiple(int keyCode, int repeatCount, @NonNull KeyEvent event) {
return false;
}
@@ -644,7 +641,7 @@
* @param event Description of the key event.
* @return True if the key shortcut was handled.
*/
- public boolean onKeyShortcut(int keyCode, KeyEvent event) {
+ public boolean onKeyShortcut(int keyCode, @NonNull KeyEvent event) {
return false;
}
@@ -658,7 +655,7 @@
* The default implementation will cancel the dialog when a touch
* happens outside of the window bounds.
*/
- public boolean onTouchEvent(MotionEvent event) {
+ public boolean onTouchEvent(@NonNull MotionEvent event) {
if (mCancelable && mShowing && mWindow.shouldCloseOnTouch(mContext, event)) {
cancel();
return true;
@@ -681,7 +678,7 @@
* @return Return true if you have consumed the event, false if you haven't.
* The default implementation always returns false.
*/
- public boolean onTrackballEvent(MotionEvent event) {
+ public boolean onTrackballEvent(@NonNull MotionEvent event) {
return false;
}
@@ -710,25 +707,30 @@
* @return Return true if you have consumed the event, false if you haven't.
* The default implementation always returns false.
*/
- public boolean onGenericMotionEvent(MotionEvent event) {
+ public boolean onGenericMotionEvent(@NonNull MotionEvent event) {
return false;
}
+ @Override
public void onWindowAttributesChanged(WindowManager.LayoutParams params) {
if (mDecor != null) {
mWindowManager.updateViewLayout(mDecor, params);
}
}
+ @Override
public void onContentChanged() {
}
+ @Override
public void onWindowFocusChanged(boolean hasFocus) {
}
+ @Override
public void onAttachedToWindow() {
}
+ @Override
public void onDetachedFromWindow() {
}
@@ -747,7 +749,8 @@
*
* @return boolean Return true if this event was consumed.
*/
- public boolean dispatchKeyEvent(KeyEvent event) {
+ @Override
+ public boolean dispatchKeyEvent(@NonNull KeyEvent event) {
if ((mOnKeyListener != null) && (mOnKeyListener.onKey(this, event.getKeyCode(), event))) {
return true;
}
@@ -767,7 +770,8 @@
* @param event The key shortcut event.
* @return True if this event was consumed.
*/
- public boolean dispatchKeyShortcutEvent(KeyEvent event) {
+ @Override
+ public boolean dispatchKeyShortcutEvent(@NonNull KeyEvent event) {
if (mWindow.superDispatchKeyShortcutEvent(event)) {
return true;
}
@@ -784,7 +788,8 @@
*
* @return boolean Return true if this event was consumed.
*/
- public boolean dispatchTouchEvent(MotionEvent ev) {
+ @Override
+ public boolean dispatchTouchEvent(@NonNull MotionEvent ev) {
if (mWindow.superDispatchTouchEvent(ev)) {
return true;
}
@@ -801,7 +806,8 @@
*
* @return boolean Return true if this event was consumed.
*/
- public boolean dispatchTrackballEvent(MotionEvent ev) {
+ @Override
+ public boolean dispatchTrackballEvent(@NonNull MotionEvent ev) {
if (mWindow.superDispatchTrackballEvent(ev)) {
return true;
}
@@ -818,14 +824,16 @@
*
* @return boolean Return true if this event was consumed.
*/
- public boolean dispatchGenericMotionEvent(MotionEvent ev) {
+ @Override
+ public boolean dispatchGenericMotionEvent(@NonNull MotionEvent ev) {
if (mWindow.superDispatchGenericMotionEvent(ev)) {
return true;
}
return onGenericMotionEvent(ev);
}
- public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
+ @Override
+ public boolean dispatchPopulateAccessibilityEvent(@NonNull AccessibilityEvent event) {
event.setClassName(getClass().getName());
event.setPackageName(mContext.getPackageName());
@@ -840,6 +848,7 @@
/**
* @see Activity#onCreatePanelView(int)
*/
+ @Override
public View onCreatePanelView(int featureId) {
return null;
}
@@ -847,7 +856,8 @@
/**
* @see Activity#onCreatePanelMenu(int, Menu)
*/
- public boolean onCreatePanelMenu(int featureId, Menu menu) {
+ @Override
+ public boolean onCreatePanelMenu(int featureId, @NonNull Menu menu) {
if (featureId == Window.FEATURE_OPTIONS_PANEL) {
return onCreateOptionsMenu(menu);
}
@@ -858,10 +868,10 @@
/**
* @see Activity#onPreparePanel(int, View, Menu)
*/
+ @Override
public boolean onPreparePanel(int featureId, View view, Menu menu) {
if (featureId == Window.FEATURE_OPTIONS_PANEL && menu != null) {
- boolean goforit = onPrepareOptionsMenu(menu);
- return goforit && menu.hasVisibleItems();
+ return onPrepareOptionsMenu(menu) && menu.hasVisibleItems();
}
return true;
}
@@ -869,6 +879,7 @@
/**
* @see Activity#onMenuOpened(int, Menu)
*/
+ @Override
public boolean onMenuOpened(int featureId, Menu menu) {
if (featureId == Window.FEATURE_ACTION_BAR) {
mActionBar.dispatchMenuVisibilityChanged(true);
@@ -879,6 +890,7 @@
/**
* @see Activity#onMenuItemSelected(int, MenuItem)
*/
+ @Override
public boolean onMenuItemSelected(int featureId, MenuItem item) {
return false;
}
@@ -886,6 +898,7 @@
/**
* @see Activity#onPanelClosed(int, Menu)
*/
+ @Override
public void onPanelClosed(int featureId, Menu menu) {
if (featureId == Window.FEATURE_ACTION_BAR) {
mActionBar.dispatchMenuVisibilityChanged(false);
@@ -900,7 +913,7 @@
* @see Activity#onCreateOptionsMenu(Menu)
* @see #getOwnerActivity()
*/
- public boolean onCreateOptionsMenu(Menu menu) {
+ public boolean onCreateOptionsMenu(@NonNull Menu menu) {
return true;
}
@@ -912,21 +925,21 @@
* @see Activity#onPrepareOptionsMenu(Menu)
* @see #getOwnerActivity()
*/
- public boolean onPrepareOptionsMenu(Menu menu) {
+ public boolean onPrepareOptionsMenu(@NonNull Menu menu) {
return true;
}
/**
* @see Activity#onOptionsItemSelected(MenuItem)
*/
- public boolean onOptionsItemSelected(MenuItem item) {
+ public boolean onOptionsItemSelected(@NonNull MenuItem item) {
return false;
}
/**
* @see Activity#onOptionsMenuClosed(Menu)
*/
- public void onOptionsMenuClosed(Menu menu) {
+ public void onOptionsMenuClosed(@NonNull Menu menu) {
}
/**
@@ -959,47 +972,49 @@
/**
* @see Activity#onCreateContextMenu(ContextMenu, View, ContextMenuInfo)
*/
+ @Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
}
/**
* @see Activity#registerForContextMenu(View)
*/
- public void registerForContextMenu(View view) {
+ public void registerForContextMenu(@NonNull View view) {
view.setOnCreateContextMenuListener(this);
}
/**
* @see Activity#unregisterForContextMenu(View)
*/
- public void unregisterForContextMenu(View view) {
+ public void unregisterForContextMenu(@NonNull View view) {
view.setOnCreateContextMenuListener(null);
}
/**
* @see Activity#openContextMenu(View)
*/
- public void openContextMenu(View view) {
+ public void openContextMenu(@NonNull View view) {
view.showContextMenu();
}
/**
* @see Activity#onContextItemSelected(MenuItem)
*/
- public boolean onContextItemSelected(MenuItem item) {
+ public boolean onContextItemSelected(@NonNull MenuItem item) {
return false;
}
/**
* @see Activity#onContextMenuClosed(Menu)
*/
- public void onContextMenuClosed(Menu menu) {
+ public void onContextMenuClosed(@NonNull Menu menu) {
}
/**
* This hook is called when the user signals the desire to start a search.
*/
- public boolean onSearchRequested(SearchEvent searchEvent) {
+ @Override
+ public boolean onSearchRequested(@NonNull SearchEvent searchEvent) {
mSearchEvent = searchEvent;
return onSearchRequested();
}
@@ -1007,6 +1022,7 @@
/**
* This hook is called when the user signals the desire to start a search.
*/
+ @Override
public boolean onSearchRequested() {
final SearchManager searchManager = (SearchManager) mContext
.getSystemService(Context.SEARCH_SERVICE);
@@ -1029,13 +1045,10 @@
* @return SearchEvent The SearchEvent that triggered the {@link
* #onSearchRequested} callback.
*/
- public final SearchEvent getSearchEvent() {
+ public final @Nullable SearchEvent getSearchEvent() {
return mSearchEvent;
}
- /**
- * {@inheritDoc}
- */
@Override
public ActionMode onWindowStartingActionMode(ActionMode.Callback callback) {
if (mActionBar != null && mActionModeTypeStarting == ActionMode.TYPE_PRIMARY) {
@@ -1044,9 +1057,6 @@
return null;
}
- /**
- * {@inheritDoc}
- */
@Override
public ActionMode onWindowStartingActionMode(ActionMode.Callback callback, int type) {
try {
@@ -1063,6 +1073,7 @@
* Note that if you override this method you should always call through
* to the superclass implementation by calling super.onActionModeStarted(mode).
*/
+ @Override
@CallSuper
public void onActionModeStarted(ActionMode mode) {
mActionMode = mode;
@@ -1074,6 +1085,7 @@
* Note that if you override this method you should always call through
* to the superclass implementation by calling super.onActionModeFinished(mode).
*/
+ @Override
@CallSuper
public void onActionModeFinished(ActionMode mode) {
if (mode == mActionMode) {
@@ -1139,7 +1151,7 @@
* Convenience for calling
* {@link android.view.Window#setFeatureDrawableUri}.
*/
- public final void setFeatureDrawableUri(int featureId, Uri uri) {
+ public final void setFeatureDrawableUri(int featureId, @Nullable Uri uri) {
getWindow().setFeatureDrawableUri(featureId, uri);
}
@@ -1147,7 +1159,7 @@
* Convenience for calling
* {@link android.view.Window#setFeatureDrawable(int, Drawable)}.
*/
- public final void setFeatureDrawable(int featureId, Drawable drawable) {
+ public final void setFeatureDrawable(int featureId, @Nullable Drawable drawable) {
getWindow().setFeatureDrawable(featureId, drawable);
}
@@ -1159,7 +1171,7 @@
getWindow().setFeatureDrawableAlpha(featureId, alpha);
}
- public LayoutInflater getLayoutInflater() {
+ public @NonNull LayoutInflater getLayoutInflater() {
return getWindow().getLayoutInflater();
}
@@ -1191,6 +1203,7 @@
* Cancel the dialog. This is essentially the same as calling {@link #dismiss()}, but it will
* also call your {@link DialogInterface.OnCancelListener} (if registered).
*/
+ @Override
public void cancel() {
if (!mCanceled && mCancelMessage != null) {
mCanceled = true;
@@ -1211,7 +1224,7 @@
*
* @param listener The {@link DialogInterface.OnCancelListener} to use.
*/
- public void setOnCancelListener(final OnCancelListener listener) {
+ public void setOnCancelListener(@Nullable OnCancelListener listener) {
if (mCancelAndDismissTaken != null) {
throw new IllegalStateException(
"OnCancelListener is already taken by "
@@ -1229,7 +1242,7 @@
* @param msg The msg to send when the dialog is canceled.
* @see #setOnCancelListener(android.content.DialogInterface.OnCancelListener)
*/
- public void setCancelMessage(final Message msg) {
+ public void setCancelMessage(@Nullable Message msg) {
mCancelMessage = msg;
}
@@ -1237,7 +1250,7 @@
* Set a listener to be invoked when the dialog is dismissed.
* @param listener The {@link DialogInterface.OnDismissListener} to use.
*/
- public void setOnDismissListener(final OnDismissListener listener) {
+ public void setOnDismissListener(@Nullable OnDismissListener listener) {
if (mCancelAndDismissTaken != null) {
throw new IllegalStateException(
"OnDismissListener is already taken by "
@@ -1254,7 +1267,7 @@
* Sets a listener to be invoked when the dialog is shown.
* @param listener The {@link DialogInterface.OnShowListener} to use.
*/
- public void setOnShowListener(OnShowListener listener) {
+ public void setOnShowListener(@Nullable OnShowListener listener) {
if (listener != null) {
mShowMessage = mListenersHandler.obtainMessage(SHOW, listener);
} else {
@@ -1266,13 +1279,13 @@
* Set a message to be sent when the dialog is dismissed.
* @param msg The msg to send when the dialog is dismissed.
*/
- public void setDismissMessage(final Message msg) {
+ public void setDismissMessage(@Nullable Message msg) {
mDismissMessage = msg;
}
/** @hide */
- public boolean takeCancelAndDismissListeners(String msg, final OnCancelListener cancel,
- final OnDismissListener dismiss) {
+ public boolean takeCancelAndDismissListeners(@Nullable String msg,
+ @Nullable OnCancelListener cancel, @Nullable OnDismissListener dismiss) {
if (mCancelAndDismissTaken != null) {
mCancelAndDismissTaken = null;
} else if (mCancelMessage != null || mDismissMessage != null) {
@@ -1306,15 +1319,15 @@
/**
* Sets the callback that will be called if a key is dispatched to the dialog.
*/
- public void setOnKeyListener(final OnKeyListener onKeyListener) {
+ public void setOnKeyListener(@Nullable OnKeyListener onKeyListener) {
mOnKeyListener = onKeyListener;
}
private static final class ListenersHandler extends Handler {
- private WeakReference<DialogInterface> mDialog;
+ private final WeakReference<DialogInterface> mDialog;
public ListenersHandler(Dialog dialog) {
- mDialog = new WeakReference<DialogInterface>(dialog);
+ mDialog = new WeakReference<>(dialog);
}
@Override
diff --git a/core/java/android/app/DownloadManager.java b/core/java/android/app/DownloadManager.java
index 8bc1aa3..e681d47 100644
--- a/core/java/android/app/DownloadManager.java
+++ b/core/java/android/app/DownloadManager.java
@@ -1380,7 +1380,7 @@
if (destinationType == Downloads.Impl.DESTINATION_FILE_URI ||
destinationType == Downloads.Impl.DESTINATION_EXTERNAL ||
destinationType == Downloads.Impl.DESTINATION_NON_DOWNLOADMANAGER_DOWNLOAD) {
- String localPath = getString(getColumnIndex(COLUMN_LOCAL_FILENAME));
+ String localPath = super.getString(getColumnIndex(COLUMN_LOCAL_FILENAME));
if (localPath == null) {
return null;
}
diff --git a/core/java/android/app/EnterTransitionCoordinator.java b/core/java/android/app/EnterTransitionCoordinator.java
index d89c0e0..a599584 100644
--- a/core/java/android/app/EnterTransitionCoordinator.java
+++ b/core/java/android/app/EnterTransitionCoordinator.java
@@ -244,6 +244,10 @@
}
}
+ public boolean isWaitingForRemoteExit() {
+ return mIsReturning && mResultReceiver != null;
+ }
+
/**
* This is called onResume. If an Activity is resuming and the transitions
* haven't started yet, force the views to appear. This is likely to be
@@ -288,6 +292,10 @@
cancelPendingTransitions();
}
mAreViewsReady = true;
+ if (mResultReceiver != null) {
+ mResultReceiver.send(MSG_CANCEL, null);
+ mResultReceiver = null;
+ }
}
private void cancel() {
diff --git a/core/java/android/app/ExitTransitionCoordinator.java b/core/java/android/app/ExitTransitionCoordinator.java
index ce017f6..0404288 100644
--- a/core/java/android/app/ExitTransitionCoordinator.java
+++ b/core/java/android/app/ExitTransitionCoordinator.java
@@ -100,6 +100,10 @@
mExitSharedElementBundle = resultData;
sharedElementExitBack();
break;
+ case MSG_CANCEL:
+ mIsCanceled = true;
+ finish();
+ break;
}
}
diff --git a/core/java/android/app/Fragment.java b/core/java/android/app/Fragment.java
index f7a4557..c745644 100644
--- a/core/java/android/app/Fragment.java
+++ b/core/java/android/app/Fragment.java
@@ -1033,11 +1033,11 @@
* false if it is not.
*/
public void setUserVisibleHint(boolean isVisibleToUser) {
- if (!mUserVisibleHint && isVisibleToUser && mState < STARTED && mFragmentManager != null) {
+ if (!mUserVisibleHint && isVisibleToUser && mState < STARTED && isAdded()) {
mFragmentManager.performPendingDeferredStart(this);
}
mUserVisibleHint = isVisibleToUser;
- mDeferStart = !isVisibleToUser;
+ mDeferStart = mState < STARTED && !isVisibleToUser;
}
/**
@@ -1582,21 +1582,21 @@
/**
* Called when the Fragment's activity changes from fullscreen mode to multi-window mode and
- * visa-versa. This is generally tied to {@link Activity#onMultiWindowChanged} of the containing
- * Activity.
+ * visa-versa. This is generally tied to {@link Activity#onMultiWindowModeChanged} of the
+ * containing Activity.
*
- * @param inMultiWindow True if the activity is in multi-window mode.
+ * @param isInMultiWindowMode True if the activity is in multi-window mode.
*/
- public void onMultiWindowChanged(boolean inMultiWindow) {
+ public void onMultiWindowModeChanged(boolean isInMultiWindowMode) {
}
/**
* Called by the system when the activity changes to and from picture-in-picture mode. This is
- * generally tied to {@link Activity#onPictureInPictureChanged} of the containing Activity.
+ * generally tied to {@link Activity#onPictureInPictureModeChanged} of the containing Activity.
*
- * @param inPictureInPicture True if the activity is in picture-in-picture mode.
+ * @param isInPictureInPictureMode True if the activity is in picture-in-picture mode.
*/
- public void onPictureInPictureChanged(boolean inPictureInPicture) {
+ public void onPictureInPictureModeChanged(boolean isInPictureInPictureMode) {
}
public void onConfigurationChanged(Configuration newConfig) {
@@ -2334,17 +2334,17 @@
}
}
- void performMultiWindowChanged(boolean inMultiWindow) {
- onMultiWindowChanged(inMultiWindow);
+ void performMultiWindowModeChanged(boolean isInMultiWindowMode) {
+ onMultiWindowModeChanged(isInMultiWindowMode);
if (mChildFragmentManager != null) {
- mChildFragmentManager.dispatchMultiWindowChanged(inMultiWindow);
+ mChildFragmentManager.dispatchMultiWindowModeChanged(isInMultiWindowMode);
}
}
- void performPictureInPictureChanged(boolean inPictureInPicture) {
- onPictureInPictureChanged(inPictureInPicture);
+ void performPictureInPictureModeChanged(boolean isInPictureInPictureMode) {
+ onPictureInPictureModeChanged(isInPictureInPictureMode);
if (mChildFragmentManager != null) {
- mChildFragmentManager.dispatchPictureInPictureChanged(inPictureInPicture);
+ mChildFragmentManager.dispatchPictureInPictureModeChanged(isInPictureInPictureMode);
}
}
diff --git a/core/java/android/app/FragmentController.java b/core/java/android/app/FragmentController.java
index 57b0ff1..b3d2df5 100644
--- a/core/java/android/app/FragmentController.java
+++ b/core/java/android/app/FragmentController.java
@@ -247,10 +247,10 @@
* the activity changed.
* <p>Call when the multi-window mode of the activity changed.
*
- * @see Fragment#onMultiWindowChanged
+ * @see Fragment#onMultiWindowModeChanged
*/
- public void dispatchMultiWindowChanged(boolean inMultiWindow) {
- mHost.mFragmentManager.dispatchMultiWindowChanged(inMultiWindow);
+ public void dispatchMultiWindowModeChanged(boolean isInMultiWindowMode) {
+ mHost.mFragmentManager.dispatchMultiWindowModeChanged(isInMultiWindowMode);
}
/**
@@ -258,10 +258,10 @@
* mode of the activity changed.
* <p>Call when the picture-in-picture mode of the activity changed.
*
- * @see Fragment#onPictureInPictureChanged
+ * @see Fragment#onPictureInPictureModeChanged
*/
- public void dispatchPictureInPictureChanged(boolean inPictureInPicture) {
- mHost.mFragmentManager.dispatchPictureInPictureChanged(inPictureInPicture);
+ public void dispatchPictureInPictureModeChanged(boolean isInPictureInPictureMode) {
+ mHost.mFragmentManager.dispatchPictureInPictureModeChanged(isInPictureInPictureMode);
}
/**
diff --git a/core/java/android/app/FragmentManager.java b/core/java/android/app/FragmentManager.java
index 2852baf..8369f17 100644
--- a/core/java/android/app/FragmentManager.java
+++ b/core/java/android/app/FragmentManager.java
@@ -2069,26 +2069,26 @@
mParent = null;
}
- public void dispatchMultiWindowChanged(boolean inMultiWindow) {
+ public void dispatchMultiWindowModeChanged(boolean isInMultiWindowMode) {
if (mAdded == null) {
return;
}
for (int i = mAdded.size() - 1; i >= 0; --i) {
final Fragment f = mAdded.get(i);
if (f != null) {
- f.performMultiWindowChanged(inMultiWindow);
+ f.performMultiWindowModeChanged(isInMultiWindowMode);
}
}
}
- public void dispatchPictureInPictureChanged(boolean inPictureInPicture) {
+ public void dispatchPictureInPictureModeChanged(boolean isInPictureInPictureMode) {
if (mAdded == null) {
return;
}
for (int i = mAdded.size() - 1; i >= 0; --i) {
final Fragment f = mAdded.get(i);
if (f != null) {
- f.performPictureInPictureChanged(inPictureInPicture);
+ f.performPictureInPictureModeChanged(isInPictureInPictureMode);
}
}
}
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index 417c0679..8ee6fd0 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -623,11 +623,11 @@
public int getAppStartMode(int uid, String packageName) throws RemoteException;
- public boolean inMultiWindow(IBinder token) throws RemoteException;
+ public boolean isInMultiWindowMode(IBinder token) throws RemoteException;
- public boolean inPictureInPicture(IBinder token) throws RemoteException;
+ public boolean isInPictureInPictureMode(IBinder token) throws RemoteException;
- public void enterPictureInPicture(IBinder token) throws RemoteException;
+ public void enterPictureInPictureMode(IBinder token) throws RemoteException;
public int setVrMode(IBinder token, boolean enabled, ComponentName packageName)
throws RemoteException;
diff --git a/core/java/android/app/IApplicationThread.java b/core/java/android/app/IApplicationThread.java
index 628bde0..a3b2638 100644
--- a/core/java/android/app/IApplicationThread.java
+++ b/core/java/android/app/IApplicationThread.java
@@ -158,8 +158,8 @@
void notifyCleartextNetwork(byte[] firstPacket) throws RemoteException;
void startBinderTracking() throws RemoteException;
void stopBinderTrackingAndDump(FileDescriptor fd) throws RemoteException;
- void scheduleMultiWindowChanged(IBinder token, boolean multiWindowMode) throws RemoteException;
- void schedulePictureInPictureChanged(IBinder token, boolean multiWindowMode) throws RemoteException;
+ void scheduleMultiWindowModeChanged(IBinder token, boolean isInMultiWindowMode) throws RemoteException;
+ void schedulePictureInPictureModeChanged(IBinder token, boolean isInPictureInPictureMode) throws RemoteException;
void scheduleLocalVoiceInteractionStarted(IBinder token, IVoiceInteractor voiceInteractor) throws RemoteException;
String descriptor = "android.app.IApplicationThread";
diff --git a/core/java/android/app/ResourcesManager.java b/core/java/android/app/ResourcesManager.java
index 54d813d..4c4f128 100644
--- a/core/java/android/app/ResourcesManager.java
+++ b/core/java/android/app/ResourcesManager.java
@@ -66,7 +66,7 @@
}
};
- private String[] mSystemLocales = {};
+ private String[] mSystemLocales = null;
private final HashSet<String> mNonSystemLocales = new HashSet<>();
private boolean mHasNonSystemLocales = false;
@@ -94,9 +94,18 @@
private final ArrayList<WeakReference<Resources>> mResourceReferences = new ArrayList<>();
/**
- * Each Activity may have only one Resources object.
+ * Resources and base configuration override associated with an Activity.
*/
- private final WeakHashMap<IBinder, WeakReference<Resources>> mActivityResourceReferences =
+ private static class ActivityResources {
+ public final Configuration overrideConfig = new Configuration();
+ public final ArrayList<WeakReference<Resources>> activityResources = new ArrayList<>();
+ }
+
+ /**
+ * Each Activity may has a base override configuration that is applied to each Resources object,
+ * which in turn may have their own override configuration specified.
+ */
+ private final WeakHashMap<IBinder, ActivityResources> mActivityResourceReferences =
new WeakHashMap<>();
/**
@@ -115,18 +124,20 @@
}
public Configuration getConfiguration() {
- return mResConfiguration;
+ synchronized (this) {
+ return mResConfiguration;
+ }
}
- DisplayMetrics getDisplayMetricsLocked() {
- return getDisplayMetricsLocked(Display.DEFAULT_DISPLAY);
+ DisplayMetrics getDisplayMetrics() {
+ return getDisplayMetrics(Display.DEFAULT_DISPLAY);
}
/**
* Protected so that tests can override and returns something a fixed value.
*/
@VisibleForTesting
- protected DisplayMetrics getDisplayMetricsLocked(int displayId) {
+ protected DisplayMetrics getDisplayMetrics(int displayId) {
DisplayMetrics dm = new DisplayMetrics();
final Display display =
getAdjustedDisplay(displayId, DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS);
@@ -272,10 +283,9 @@
return config;
}
-
private ResourcesImpl createResourcesImpl(@NonNull ResourcesKey key) {
AssetManager assets = createAssetManager(key);
- DisplayMetrics dm = getDisplayMetricsLocked(key.mDisplayId);
+ DisplayMetrics dm = getDisplayMetrics(key.mDisplayId);
Configuration config = generateConfig(key, dm);
ResourcesImpl impl = new ResourcesImpl(assets, dm, config, key.mCompatInfo);
if (DEBUG) {
@@ -290,7 +300,7 @@
* @param key The key to match.
* @return a ResourcesImpl if the key matches a cache entry, null otherwise.
*/
- private ResourcesImpl findResourcesImplForKey(@NonNull ResourcesKey key) {
+ private ResourcesImpl findResourcesImplForKeyLocked(@NonNull ResourcesKey key) {
WeakReference<ResourcesImpl> weakImplRef = mResourceImpls.get(key);
ResourcesImpl impl = weakImplRef != null ? weakImplRef.get() : null;
if (impl != null && impl.getAssets().isUpToDate()) {
@@ -303,7 +313,7 @@
* Find the ResourcesKey that this ResourcesImpl object is associated with.
* @return the ResourcesKey or null if none was found.
*/
- private ResourcesKey findKeyForResourceImpl(@NonNull ResourcesImpl resourceImpl) {
+ private ResourcesKey findKeyForResourceImplLocked(@NonNull ResourcesImpl resourceImpl) {
final int refCount = mResourceImpls.size();
for (int i = 0; i < refCount; i++) {
WeakReference<ResourcesImpl> weakImplRef = mResourceImpls.valueAt(i);
@@ -315,36 +325,46 @@
return null;
}
+ private ActivityResources getOrCreateActivityResourcesStructLocked(
+ @NonNull IBinder activityToken) {
+ ActivityResources activityResources = mActivityResourceReferences.get(activityToken);
+ if (activityResources == null) {
+ activityResources = new ActivityResources();
+ mActivityResourceReferences.put(activityToken, activityResources);
+ }
+ return activityResources;
+ }
+
/**
* Gets an existing Resources object tied to this Activity, or creates one if it doesn't exist
* or the class loader is different.
*/
private Resources getOrCreateResourcesForActivityLocked(@NonNull IBinder activityToken,
@NonNull ClassLoader classLoader, @NonNull ResourcesImpl impl) {
- // This is a request tied to an Activity, meaning we will need to update all
- // Activity related Resources to match this configuration.
- WeakReference<Resources> weakResourceRef = mActivityResourceReferences.get(activityToken);
- Resources resources = weakResourceRef != null ? weakResourceRef.get() : null;
- if (resources == null || !Objects.equals(resources.getClassLoader(), classLoader)) {
- resources = new Resources(classLoader);
- mActivityResourceReferences.put(activityToken, new WeakReference<>(resources));
- if (DEBUG) {
- Slog.d(TAG, "- creating new ref=" + resources);
- }
- } else {
- if (DEBUG) {
- Slog.d(TAG, "- using existing ref=" + resources);
+ final ActivityResources activityResources = getOrCreateActivityResourcesStructLocked(
+ activityToken);
+
+ final int refCount = activityResources.activityResources.size();
+ for (int i = 0; i < refCount; i++) {
+ WeakReference<Resources> weakResourceRef = activityResources.activityResources.get(i);
+ Resources resources = weakResourceRef.get();
+
+ if (resources != null
+ && Objects.equals(resources.getClassLoader(), classLoader)
+ && resources.getImpl() == impl) {
+ if (DEBUG) {
+ Slog.d(TAG, "- using existing ref=" + resources);
+ }
+ return resources;
}
}
- if (resources.getImpl() != impl) {
- if (DEBUG) {
- Slog.d(TAG, "- setting ref=" + resources + " with impl=" + impl);
- }
-
- // Setting an impl is expensive because we update all ThemeImpl references.
- // too.
- resources.setImpl(impl);
+ Resources resources = new Resources(classLoader);
+ resources.setImpl(impl);
+ activityResources.activityResources.add(new WeakReference<>(resources));
+ if (DEBUG) {
+ Slog.d(TAG, "- creating new ref=" + resources);
+ Slog.d(TAG, "- setting ref=" + resources + " with impl=" + impl);
}
return resources;
}
@@ -359,7 +379,7 @@
final int refCount = mResourceReferences.size();
for (int i = 0; i < refCount; i++) {
WeakReference<Resources> weakResourceRef = mResourceReferences.get(i);
- Resources resources = weakResourceRef != null ? weakResourceRef.get() : null;
+ Resources resources = weakResourceRef.get();
if (resources != null &&
Objects.equals(resources.getClassLoader(), classLoader) &&
resources.getImpl() == impl) {
@@ -382,6 +402,182 @@
}
/**
+ * Creates base resources for an Activity. Calls to
+ * {@link #getResources(IBinder, String, String[], String[], String[], int, Configuration,
+ * CompatibilityInfo, ClassLoader)} with the same activityToken will have their override
+ * configurations merged with the one specified here.
+ *
+ * @param activityToken Represents an Activity.
+ * @param resDir The base resource path. Can be null (only framework resources will be loaded).
+ * @param splitResDirs An array of split resource paths. Can be null.
+ * @param overlayDirs An array of overlay paths. Can be null.
+ * @param libDirs An array of resource library paths. Can be null.
+ * @param displayId The ID of the display for which to create the resources.
+ * @param overrideConfig The configuration to apply on top of the base configuration. Can be
+ * null. This provides the base override for this Activity.
+ * @param compatInfo The compatibility settings to use. Cannot be null. A default to use is
+ * {@link CompatibilityInfo#DEFAULT_COMPATIBILITY_INFO}.
+ * @param classLoader The class loader to use when inflating Resources. If null, the
+ * {@link ClassLoader#getSystemClassLoader()} is used.
+ * @return a Resources object from which to access resources.
+ */
+ public Resources createBaseActivityResources(@NonNull IBinder activityToken,
+ @Nullable String resDir,
+ @Nullable String[] splitResDirs,
+ @Nullable String[] overlayDirs,
+ @Nullable String[] libDirs,
+ int displayId,
+ @Nullable Configuration overrideConfig,
+ @NonNull CompatibilityInfo compatInfo,
+ @Nullable ClassLoader classLoader) {
+ final ResourcesKey key = new ResourcesKey(
+ resDir,
+ splitResDirs,
+ overlayDirs,
+ libDirs,
+ displayId,
+ overrideConfig != null ? new Configuration(overrideConfig) : null, // Copy
+ compatInfo);
+ classLoader = classLoader != null ? classLoader : ClassLoader.getSystemClassLoader();
+
+ if (DEBUG) {
+ Slog.d(TAG, "createBaseActivityResources activity=" + activityToken
+ + " with key=" + key);
+ }
+
+ synchronized (this) {
+ final ActivityResources activityResources = getOrCreateActivityResourcesStructLocked(
+ activityToken);
+
+ if (overrideConfig != null) {
+ activityResources.overrideConfig.setTo(overrideConfig);
+ } else {
+ activityResources.overrideConfig.setToDefaults();
+ }
+ }
+
+ // Update any existing Activity Resources references.
+ updateResourcesForActivity(activityToken, overrideConfig);
+
+ // Now request an actual Resources object.
+ return getOrCreateResources(activityToken, key, classLoader);
+ }
+
+ /**
+ * Gets an existing Resources object set with a ResourcesImpl object matching the given key,
+ * or creates one if it doesn't exist.
+ *
+ * @param activityToken The Activity this Resources object should be associated with.
+ * @param key The key describing the parameters of the ResourcesImpl object.
+ * @param classLoader The classloader to use for the Resources object.
+ * If null, {@link ClassLoader#getSystemClassLoader()} is used.
+ * @return A Resources object that gets updated when
+ * {@link #applyConfigurationToResourcesLocked(Configuration, CompatibilityInfo)}
+ * is called.
+ */
+ private Resources getOrCreateResources(@Nullable IBinder activityToken,
+ @NonNull ResourcesKey key, @NonNull ClassLoader classLoader) {
+ final boolean findSystemLocales;
+ final boolean hasNonSystemLocales;
+ synchronized (this) {
+ findSystemLocales = (mSystemLocales == null || mSystemLocales.length == 0);
+ hasNonSystemLocales = mHasNonSystemLocales;
+
+ if (DEBUG) {
+ Throwable here = new Throwable();
+ here.fillInStackTrace();
+ Slog.w(TAG, "!! Get resources for activity=" + activityToken + " key=" + key, here);
+ }
+
+ if (activityToken != null) {
+ final ActivityResources activityResources = getOrCreateActivityResourcesStructLocked(
+ activityToken);
+
+ // Clean up any dead references so they don't pile up.
+ ArrayUtils.unstableRemoveIf(activityResources.activityResources,
+ sEmptyReferencePredicate);
+
+ // Rebase the key's override config on top of the Activity's base override.
+ if (key.hasOverrideConfiguration()
+ && !activityResources.overrideConfig.equals(Configuration.EMPTY)) {
+ final Configuration temp = new Configuration(activityResources.overrideConfig);
+ temp.updateFrom(key.mOverrideConfiguration);
+ key.mOverrideConfiguration.setTo(temp);
+ }
+
+ ResourcesImpl resourcesImpl = findResourcesImplForKeyLocked(key);
+ if (resourcesImpl != null) {
+ if (DEBUG) {
+ Slog.d(TAG, "- using existing impl=" + resourcesImpl);
+ }
+ return getOrCreateResourcesForActivityLocked(activityToken, classLoader,
+ resourcesImpl);
+ }
+
+ // We will create the ResourcesImpl object outside of holding this lock.
+
+ } else {
+ // Clean up any dead references so they don't pile up.
+ ArrayUtils.unstableRemoveIf(mResourceReferences, sEmptyReferencePredicate);
+
+ // Not tied to an Activity, find a shared Resources that has the right ResourcesImpl
+ ResourcesImpl resourcesImpl = findResourcesImplForKeyLocked(key);
+ if (resourcesImpl != null) {
+ if (DEBUG) {
+ Slog.d(TAG, "- using existing impl=" + resourcesImpl);
+ }
+ return getOrCreateResourcesLocked(classLoader, resourcesImpl);
+ }
+
+ // We will create the ResourcesImpl object outside of holding this lock.
+ }
+ }
+
+ // If we're here, we didn't find a suitable ResourcesImpl to use, so create one now.
+ ResourcesImpl resourcesImpl = createResourcesImpl(key);
+
+ final String[] systemLocales = findSystemLocales
+ ? AssetManager.getSystem().getLocales() : null;
+ final String[] nonSystemLocales = resourcesImpl.getAssets().getNonSystemLocales();
+ // Avoid checking for non-pseudo-locales if we already know there were some from a previous
+ // Resources. The default value (for when hasNonSystemLocales is true) doesn't matter,
+ // since mHasNonSystemLocales will also be true, and thus isPseudoLocalesOnly would not be
+ // able to affect mHasNonSystemLocales.
+ final boolean isPseudoLocalesOnly = hasNonSystemLocales ||
+ LocaleList.isPseudoLocalesOnly(nonSystemLocales);
+
+ synchronized (this) {
+ if (mSystemLocales == null || mSystemLocales.length == 0) {
+ mSystemLocales = systemLocales;
+ }
+ mNonSystemLocales.addAll(Arrays.asList(nonSystemLocales));
+ mHasNonSystemLocales = mHasNonSystemLocales || !isPseudoLocalesOnly;
+
+ ResourcesImpl existingResourcesImpl = findResourcesImplForKeyLocked(key);
+ if (existingResourcesImpl != null) {
+ if (DEBUG) {
+ Slog.d(TAG, "- got beat! existing impl=" + existingResourcesImpl
+ + " new impl=" + resourcesImpl);
+ }
+ resourcesImpl.getAssets().close();
+ resourcesImpl = existingResourcesImpl;
+ } else {
+ // Add this ResourcesImpl to the cache.
+ mResourceImpls.put(key, new WeakReference<>(resourcesImpl));
+ }
+
+ final Resources resources;
+ if (activityToken != null) {
+ resources = getOrCreateResourcesForActivityLocked(activityToken, classLoader,
+ resourcesImpl);
+ } else {
+ resources = getOrCreateResourcesLocked(classLoader, resourcesImpl);
+ }
+ return resources;
+ }
+ }
+
+ /**
* Gets or creates a new Resources object associated with the IBinder token. References returned
* by this method live as long as the Activity, meaning they can be cached and used by the
* Activity even after a configuration change. If any other parameter is changed
@@ -425,92 +621,8 @@
displayId,
overrideConfig != null ? new Configuration(overrideConfig) : null, // Copy
compatInfo);
-
classLoader = classLoader != null ? classLoader : ClassLoader.getSystemClassLoader();
-
- final boolean findSystemLocales;
- final boolean hasNonSystemLocales;
- synchronized (this) {
- findSystemLocales = (mSystemLocales.length == 0);
- hasNonSystemLocales = mHasNonSystemLocales;
-
- if (DEBUG) {
- Throwable here = new Throwable();
- here.fillInStackTrace();
- Slog.w(TAG, "!! Get resources for activity=" + activityToken + " key=" + key, here);
- }
-
- if (activityToken != null) {
- ResourcesImpl resourcesImpl = findResourcesImplForKey(key);
- if (resourcesImpl != null) {
- if (DEBUG) {
- Slog.d(TAG, "- using existing impl=" + resourcesImpl);
- }
- return getOrCreateResourcesForActivityLocked(activityToken, classLoader,
- resourcesImpl);
- }
-
- // We will create the ResourcesImpl object outside of holding this lock.
-
- } else {
- // Clean up any dead references so they don't pile up.
- ArrayUtils.unstableRemoveIf(mResourceReferences, sEmptyReferencePredicate);
-
- // Not tied to an Activity, find a shared Resources that has the right ResourcesImpl
- ResourcesImpl resourcesImpl = findResourcesImplForKey(key);
- if (resourcesImpl != null) {
- if (DEBUG) {
- Slog.d(TAG, "- using existing impl=" + resourcesImpl);
- }
- return getOrCreateResourcesLocked(classLoader, resourcesImpl);
- }
-
- // We will create the ResourcesImpl object outside of holding this lock.
- }
- }
-
- // If we're here, we didn't find a suitable ResourcesImpl to use, so create one now.
- ResourcesImpl resourcesImpl = createResourcesImpl(key);
-
- final String[] systemLocales = findSystemLocales
- ? AssetManager.getSystem().getLocales() : null;
- final String[] nonSystemLocales = resourcesImpl.getAssets().getNonSystemLocales();
- // Avoid checking for non-pseudo-locales if we already know there were some from a previous
- // Resources. The default value (for when hasNonSystemLocales is true) doesn't matter,
- // since mHasNonSystemLocales will also be true, and thus isPseudoLocalesOnly would not be
- // able to affect mHasNonSystemLocales.
- final boolean isPseudoLocalesOnly = hasNonSystemLocales ||
- LocaleList.isPseudoLocalesOnly(nonSystemLocales);
-
- synchronized (this) {
- if (mSystemLocales.length == 0) {
- mSystemLocales = systemLocales;
- }
- mNonSystemLocales.addAll(Arrays.asList(nonSystemLocales));
- mHasNonSystemLocales = mHasNonSystemLocales || !isPseudoLocalesOnly;
-
- ResourcesImpl existingResourcesImpl = findResourcesImplForKey(key);
- if (existingResourcesImpl != null) {
- if (DEBUG) {
- Slog.d(TAG, "- got beat! existing impl=" + existingResourcesImpl
- + " new impl=" + resourcesImpl);
- }
- resourcesImpl.getAssets().close();
- resourcesImpl = existingResourcesImpl;
- } else {
- // Add this ResourcesImpl to the cache.
- mResourceImpls.put(key, new WeakReference<>(resourcesImpl));
- }
-
- final Resources resources;
- if (activityToken != null) {
- resources = getOrCreateResourcesForActivityLocked(activityToken, classLoader,
- resourcesImpl);
- } else {
- resources = getOrCreateResourcesLocked(classLoader, resourcesImpl);
- }
- return resources;
- }
+ return getOrCreateResources(activityToken, key, classLoader);
}
/**
@@ -524,34 +636,100 @@
*/
public void updateResourcesForActivity(@NonNull IBinder activityToken,
@Nullable Configuration overrideConfig) {
- final ClassLoader classLoader;
- final ResourcesKey oldKey;
synchronized (this) {
- // Extract the ResourcesKey that was last used to create the Resources for this
- // activity.
- WeakReference<Resources> weakResRef = mActivityResourceReferences.get(activityToken);
- final Resources resources = weakResRef != null ? weakResRef.get() : null;
- if (resources == null) {
- Slog.e(TAG, "can't update resources for uncached activity " + activityToken);
+ final ActivityResources activityResources = getOrCreateActivityResourcesStructLocked(
+ activityToken);
+
+ if (Objects.equals(activityResources.overrideConfig, overrideConfig)) {
+ // They are the same, no work to do.
return;
}
- classLoader = resources.getClassLoader();
- oldKey = findKeyForResourceImpl(resources.getImpl());
- if (oldKey == null) {
- Slog.e(TAG, "can't find ResourcesKey for resources impl=" + resources.getImpl());
- return;
+ // Grab a copy of the old configuration so we can create the delta's of each
+ // Resources object associated with this Activity.
+ final Configuration oldConfig = new Configuration(activityResources.overrideConfig);
+
+ // Update the Activity's base override.
+ if (overrideConfig != null) {
+ activityResources.overrideConfig.setTo(overrideConfig);
+ } else {
+ activityResources.overrideConfig.setToDefaults();
+ }
+
+ if (DEBUG) {
+ Throwable here = new Throwable();
+ here.fillInStackTrace();
+ Slog.d(TAG, "updating resources override for activity=" + activityToken
+ + " from oldConfig=" + Configuration.resourceQualifierString(oldConfig)
+ + " to newConfig="
+ + Configuration.resourceQualifierString(activityResources.overrideConfig),
+ here);
+ }
+
+ final boolean activityHasOverrideConfig =
+ !activityResources.overrideConfig.equals(Configuration.EMPTY);
+
+ // Rebase each Resources associated with this Activity.
+ final int refCount = activityResources.activityResources.size();
+ for (int i = 0; i < refCount; i++) {
+ WeakReference<Resources> weakResRef = activityResources.activityResources.get(i);
+ Resources resources = weakResRef.get();
+ if (resources == null) {
+ continue;
+ }
+
+ // Extract the ResourcesKey that was last used to create the Resources for this
+ // activity.
+ final ResourcesKey oldKey = findKeyForResourceImplLocked(resources.getImpl());
+ if (oldKey == null) {
+ Slog.e(TAG, "can't find ResourcesKey for resources impl="
+ + resources.getImpl());
+ continue;
+ }
+
+ // Build the new override configuration for this ResourcesKey.
+ final Configuration rebasedOverrideConfig = new Configuration();
+ if (overrideConfig != null) {
+ rebasedOverrideConfig.setTo(overrideConfig);
+ }
+
+ if (activityHasOverrideConfig && oldKey.hasOverrideConfiguration()) {
+ // Generate a delta between the old base Activity override configuration and
+ // the actual final override configuration that was used to figure out the real
+ // delta this Resources object wanted.
+ Configuration overrideOverrideConfig = Configuration.generateDelta(
+ oldConfig, oldKey.mOverrideConfiguration);
+ rebasedOverrideConfig.updateFrom(overrideOverrideConfig);
+ }
+
+ // Create the new ResourcesKey with the rebased override config.
+ final ResourcesKey newKey = new ResourcesKey(oldKey.mResDir, oldKey.mSplitResDirs,
+ oldKey.mOverlayDirs, oldKey.mLibDirs, oldKey.mDisplayId,
+ rebasedOverrideConfig, oldKey.mCompatInfo);
+
+ if (DEBUG) {
+ Slog.d(TAG, "rebasing ref=" + resources + " from oldKey=" + oldKey
+ + " to newKey=" + newKey);
+ }
+
+ ResourcesImpl resourcesImpl = findResourcesImplForKeyLocked(newKey);
+ if (resourcesImpl == null) {
+ resourcesImpl = createResourcesImpl(newKey);
+ mResourceImpls.put(newKey, new WeakReference<>(resourcesImpl));
+ }
+
+ if (resourcesImpl != resources.getImpl()) {
+ // Set the ResourcesImpl, updating it for all users of this Resources object.
+ resources.setImpl(resourcesImpl);
+ }
}
}
-
- // Update the Resources object with the new override config and all of the existing
- // settings.
- getResources(activityToken, oldKey.mResDir, oldKey.mSplitResDirs, oldKey.mOverlayDirs,
- oldKey.mLibDirs, oldKey.mDisplayId, overrideConfig, oldKey.mCompatInfo,
- classLoader);
}
/* package */ void setDefaultLocalesLocked(@NonNull LocaleList locales) {
+ if (mSystemLocales == null) {
+ throw new RuntimeException("ResourcesManager is not ready to negotiate locales.");
+ }
final int bestLocale;
if (mHasNonSystemLocales) {
bestLocale = locales.getFirstMatchIndexWithEnglishSupported(mNonSystemLocales);
@@ -575,7 +753,7 @@
int changes = mResConfiguration.updateFrom(config);
// Things might have changed in display manager, so clear the cached displays.
mDisplays.clear();
- DisplayMetrics defaultDisplayMetrics = getDisplayMetricsLocked();
+ DisplayMetrics defaultDisplayMetrics = getDisplayMetrics();
if (compat != null && (mResCompatibilityInfo == null ||
!mResCompatibilityInfo.equals(compat))) {
@@ -629,7 +807,7 @@
}
tmpConfig.setTo(localeAdjustedConfig);
if (!isDefaultDisplay) {
- dm = getDisplayMetricsLocked(displayId);
+ dm = getDisplayMetrics(displayId);
applyNonDefaultDisplayMetricsToConfiguration(dm, tmpConfig);
}
if (hasOverrideConfiguration) {
@@ -649,4 +827,4 @@
return changes != 0;
}
-}
\ No newline at end of file
+}
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index 2987fbc..bdc4404 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -882,7 +882,12 @@
public final T getService(ContextImpl ctx) {
synchronized (StaticApplicationContextServiceFetcher.this) {
if (mCachedInstance == null) {
- mCachedInstance = createService(ctx.getApplicationContext());
+ Context appContext = ctx.getApplicationContext();
+ // If the application context is null, we're either in the system process or
+ // it's the application context very early in app initialization. In both these
+ // cases, the passed-in ContextImpl will not be freed, so it's safe to pass it
+ // to the service. http://b/27532714 .
+ mCachedInstance = createService(appContext != null ? appContext : ctx);
}
return mCachedInstance;
}
diff --git a/core/java/android/app/UiAutomationConnection.java b/core/java/android/app/UiAutomationConnection.java
index 276f774..2c1ee8e 100644
--- a/core/java/android/app/UiAutomationConnection.java
+++ b/core/java/android/app/UiAutomationConnection.java
@@ -36,6 +36,7 @@
import android.view.WindowContentFrameStats;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.IAccessibilityManager;
+
import libcore.io.IoUtils;
import java.io.FileOutputStream;
@@ -77,6 +78,7 @@
private int mOwningUid;
+ @Override
public void connect(IAccessibilityServiceClient client, int flags) {
if (client == null) {
throw new IllegalArgumentException("Client cannot be null!");
@@ -326,11 +328,12 @@
int flags) {
IAccessibilityManager manager = IAccessibilityManager.Stub.asInterface(
ServiceManager.getService(Context.ACCESSIBILITY_SERVICE));
- AccessibilityServiceInfo info = new AccessibilityServiceInfo();
+ final AccessibilityServiceInfo info = new AccessibilityServiceInfo();
info.eventTypes = AccessibilityEvent.TYPES_ALL_MASK;
info.feedbackType = AccessibilityServiceInfo.FEEDBACK_GENERIC;
info.flags |= AccessibilityServiceInfo.FLAG_INCLUDE_NOT_IMPORTANT_VIEWS
- | AccessibilityServiceInfo.FLAG_REPORT_VIEW_IDS;
+ | AccessibilityServiceInfo.FLAG_REPORT_VIEW_IDS
+ | AccessibilityServiceInfo.FLAG_FORCE_DIRECT_BOOT_AWARE;
info.setCapabilities(AccessibilityServiceInfo.CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT
| AccessibilityServiceInfo.CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION
| AccessibilityServiceInfo.CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY
diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java
index b52af27..72b9318 100644
--- a/core/java/android/app/WallpaperManager.java
+++ b/core/java/android/app/WallpaperManager.java
@@ -161,8 +161,8 @@
/** @hide */
@IntDef(flag = true, value = {
- FLAG_SET_SYSTEM,
- FLAG_SET_LOCK
+ FLAG_SYSTEM,
+ FLAG_LOCK
})
@Retention(RetentionPolicy.SOURCE)
public @interface SetWallpaperFlags {}
@@ -170,12 +170,12 @@
/**
* Flag: use the supplied imagery as the general system wallpaper.
*/
- public static final int FLAG_SET_SYSTEM = 1 << 0;
+ public static final int FLAG_SYSTEM = 1 << 0;
/**
* Flag: use the supplied imagery as the lock-screen wallpaper.
*/
- public static final int FLAG_SET_LOCK = 1 << 1;
+ public static final int FLAG_LOCK = 1 << 1;
private final Context mContext;
@@ -336,7 +336,7 @@
try {
Bundle params = new Bundle();
- ParcelFileDescriptor fd = mService.getWallpaper(this, FLAG_SET_SYSTEM,
+ ParcelFileDescriptor fd = mService.getWallpaper(this, FLAG_SYSTEM,
params, userId);
if (fd != null) {
try {
@@ -663,11 +663,18 @@
/**
* Get an open, readable file descriptor to the given wallpaper image file.
- * The callee is resopnsible for closing the fd when done ingesting the file.
+ * The caller is responsible for closing the file descriptor when done ingesting the file.
*
* <p>If no lock-specific wallpaper has been configured for the given user, then
- * this method will return {@code null} when requesting {@link #FLAG_SET_LOCK} rather than
+ * this method will return {@code null} when requesting {@link #FLAG_LOCK} rather than
* returning the system wallpaper's image file.
+ *
+ * @param which The wallpaper whose image file is to be retrieved. Must be a single
+ * defined kind of wallpaper, either {@link #FLAG_SYSTEM} or
+ * {@link #FLAG_LOCK}.
+ *
+ * @see #FLAG_LOCK
+ * @see #FLAG_SYSTEM
*/
public ParcelFileDescriptor getWallpaperFile(int which) {
return getWallpaperFile(which, mContext.getUserId());
@@ -677,10 +684,19 @@
* Version of {@link #getWallpaperFile(int)} that can access the wallpaper data
* for a given user. The caller must hold the INTERACT_ACROSS_USERS_FULL
* permission to access another user's wallpaper data.
+ *
+ * @param which The wallpaper whose image file is to be retrieved. Must be a single
+ * defined kind of wallpaper, either {@link #FLAG_SYSTEM} or
+ * {@link #FLAG_LOCK}.
+ * @param userId The user or profile whose imagery is to be retrieved
+ *
+ * @see #FLAG_LOCK
+ * @see #FLAG_SYSTEM
+ *
* @hide
*/
public ParcelFileDescriptor getWallpaperFile(int which, int userId) {
- if (which != FLAG_SET_SYSTEM && which != FLAG_SET_LOCK) {
+ if (which != FLAG_SYSTEM && which != FLAG_LOCK) {
throw new IllegalArgumentException("Must request exactly one kind of wallpaper");
}
@@ -730,8 +746,8 @@
* such wallpaper configured, returns a negative number.
*
* @param which The wallpaper whose ID is to be returned. Must be a single
- * defined kind of wallpaper, either {@link #FLAG_SET_SYSTEM} or
- * {@link #FLAG_SET_LOCK}.
+ * defined kind of wallpaper, either {@link #FLAG_SYSTEM} or
+ * {@link #FLAG_LOCK}.
* @return The positive numeric ID of the current wallpaper of the given kind,
* or a negative value if no such wallpaper is configured.
*/
@@ -823,24 +839,24 @@
* <p>This method requires the caller to hold the permission
* {@link android.Manifest.permission#SET_WALLPAPER}.
*
- * @param resid The bitmap to save.
+ * @param resid The resource ID of the bitmap to be used as the wallpaper image
*
* @throws IOException If an error occurs reverting to the built-in
* wallpaper.
*/
public void setResource(@RawRes int resid) throws IOException {
- setResource(resid, FLAG_SET_SYSTEM);
+ setResource(resid, FLAG_SYSTEM);
}
/**
- * Version of {@link #setResource(int)} that takes an optional Bundle for returning
- * metadata about the operation to the caller.
+ * Version of {@link #setResource(int)} that allows the caller to specify which
+ * of the supported wallpaper categories to set.
*
- * @param resid
- * @param which Flags indicating which wallpaper(s) to configure with the new imagery.
+ * @param resid The resource ID of the bitmap to be used as the wallpaper image
+ * @param which Flags indicating which wallpaper(s) to configure with the new imagery
*
- * @see #FLAG_SET_LOCK
- * @see #FLAG_SET_SYSTEM
+ * @see #FLAG_LOCK
+ * @see #FLAG_SYSTEM
*
* @return An integer ID assigned to the newly active wallpaper; or zero on failure.
*
@@ -934,11 +950,10 @@
*/
public int setBitmap(Bitmap fullImage, Rect visibleCropHint, boolean allowBackup)
throws IOException {
- return setBitmap(fullImage, visibleCropHint, allowBackup, FLAG_SET_SYSTEM);
+ return setBitmap(fullImage, visibleCropHint, allowBackup, FLAG_SYSTEM);
}
/**
- /**
* Version of {@link #setBitmap(Bitmap, Rect, boolean)} that allows the caller
* to specify which of the supported wallpaper categories to set.
*
@@ -951,8 +966,8 @@
* image for restore to a future device; {@code false} otherwise.
* @param which Flags indicating which wallpaper(s) to configure with the new imagery.
*
- * @see #FLAG_SET_LOCK
- * @see #FLAG_SET_SYSTEM
+ * @see #FLAG_LOCK
+ * @see #FLAG_SYSTEM
*
* @return An integer ID assigned to the newly active wallpaper; or zero on failure.
*
@@ -1054,7 +1069,7 @@
*/
public int setStream(InputStream bitmapData, Rect visibleCropHint, boolean allowBackup)
throws IOException {
- return setStream(bitmapData, visibleCropHint, allowBackup, FLAG_SET_SYSTEM);
+ return setStream(bitmapData, visibleCropHint, allowBackup, FLAG_SYSTEM);
}
/**
@@ -1070,8 +1085,8 @@
* image for restore to a future device; {@code false} otherwise.
* @param which Flags indicating which wallpaper(s) to configure with the new imagery.
*
- * @see #FLAG_SET_LOCK
- * @see #FLAG_SET_SYSTEM
+ * @see #FLAG_LOCK
+ * @see #FLAG_SYSTEM
*
* @throws IOException
*/
@@ -1287,7 +1302,7 @@
*/
@SystemApi
public void clearWallpaper() {
- clearWallpaper(FLAG_SET_SYSTEM, mContext.getUserId());
+ clearWallpaper(FLAG_SYSTEM, mContext.getUserId());
}
/**
@@ -1467,20 +1482,20 @@
/**
* Remove one or more currently set wallpapers, reverting to the system default
- * display for each one. If {@link #FLAG_SET_SYSTEM} is set in the {@code which}
+ * display for each one. If {@link #FLAG_SYSTEM} is set in the {@code which}
* parameter, the intent {@link Intent#ACTION_WALLPAPER_CHANGED} will be broadcast
* upon success.
*
- * @param which A bitwise combination of {@link #FLAG_SET_SYSTEM} or
- * {@link #FLAG_SET_LOCK}
+ * @param which A bitwise combination of {@link #FLAG_SYSTEM} or
+ * {@link #FLAG_LOCK}
* @throws IOException If an error occurs reverting to the built-in wallpaper.
*/
public void clear(int which) throws IOException {
- if ((which & FLAG_SET_SYSTEM) != 0) {
+ if ((which & FLAG_SYSTEM) != 0) {
clear();
}
- if ((which & FLAG_SET_LOCK) != 0) {
- clearWallpaper(FLAG_SET_LOCK, mContext.getUserId());
+ if ((which & FLAG_LOCK) != 0) {
+ clearWallpaper(FLAG_LOCK, mContext.getUserId());
}
}
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index e7427bf..b924327 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -71,6 +71,7 @@
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Set;
@@ -2184,9 +2185,6 @@
* Force a new device unlock password (the password needed to access the entire device, not for
* individual accounts) on the user. This takes effect immediately.
* <p>
- * Calling this from a managed profile that shares the password with the owner profile will
- * throw a security exception.
- * <p>
* <em>Note: This API has been limited as of {@link android.os.Build.VERSION_CODES#N} for
* device admins that are not device owner and not profile owner.
* The password can now only be changed if there is currently no password set. Device owner
@@ -2200,10 +2198,10 @@
* case the currently active quality will be increased to match.
* <p>
* Calling with a null or empty password will clear any existing PIN, pattern or password if the
- * current password constraints allow it. <em>Note: This will not
- * work in {@link android.os.Build.VERSION_CODES#N} and later for device admins that are not
- * device owner and not profile owner. Once set, the password cannot be changed to null or
- * empty, except by device owner or profile owner.</em>
+ * current password constraints allow it. <em>Note: This will not work in
+ * {@link android.os.Build.VERSION_CODES#N} and later for managed profiles, or for device admins
+ * that are not device owner or profile owner. Once set, the password cannot be changed to null
+ * or empty except by these admins.</em>
* <p>
* The calling device admin must have requested
* {@link DeviceAdminInfo#USES_POLICY_RESET_PASSWORD} to be able to call this method; if it has
@@ -2654,6 +2652,43 @@
}
/**
+ * Mark a CA certificate as approved by the device user. This means that they have been notified
+ * of the installation, were made aware of the risks, viewed the certificate and still wanted to
+ * keep the certificate on the device.
+ *
+ * Calling with {@param approval} as {@code true} will cancel any ongoing warnings related to
+ * this certificate.
+ *
+ * @hide
+ */
+ public boolean approveCaCert(String alias, int userHandle, boolean approval) {
+ if (mService != null) {
+ try {
+ return mService.approveCaCert(alias, userHandle, approval);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Check whether a CA certificate has been approved by the device user.
+ *
+ * @hide
+ */
+ public boolean isCaCertApproved(String alias, int userHandle) {
+ if (mService != null) {
+ try {
+ return mService.isCaCertApproved(alias, userHandle);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+ return false;
+ }
+
+ /**
* Installs the given certificate as a user CA.
*
* @param admin Which {@link DeviceAdminReceiver} this request is associated with, or
@@ -2782,7 +2817,7 @@
* compromised, certificates it had already installed will be protected.
*
* <p>If the installer must have access to the credentials, call
- * {@link #installKeyPair(ComponentName, PrivateKey, Certificate, String, boolean)} instead.
+ * {@link #installKeyPair(ComponentName, PrivateKey, Certificate[], String, boolean)} instead.
*
* @param admin Which {@link DeviceAdminReceiver} this request is associated with, or
* {@code null} if calling from a delegated certificate installer.
@@ -2796,13 +2831,14 @@
*/
public boolean installKeyPair(@Nullable ComponentName admin, @NonNull PrivateKey privKey,
@NonNull Certificate cert, @NonNull String alias) {
- return installKeyPair(admin, privKey, cert, alias, false);
+ return installKeyPair(admin, privKey, new Certificate[] {cert}, alias, false);
}
/**
* Called by a device or profile owner, or delegated certificate installer, to install a
- * certificate and corresponding private key. All apps within the profile will be able to access
- * the certificate and use the private key, given direct user approval.
+ * certificate chain and corresponding private key for the leaf certificate. All apps within the
+ * profile will be able to access the certificate chain and use the private key, given direct
+ * user approval.
*
* <p>The caller of this API may grant itself access to the certificate and private key
* immediately, without user approval. It is a best practice not to request this unless strictly
@@ -2811,7 +2847,9 @@
* @param admin Which {@link DeviceAdminReceiver} this request is associated with, or
* {@code null} if calling from a delegated certificate installer.
* @param privKey The private key to install.
- * @param cert The certificate to install.
+ * @param certs The certificate chain to install. The chain should start with the leaf
+ * certificate and include the chain of trust in order. This will be returned by
+ * {@link android.security.KeyChain#getCertificateChain}.
* @param alias The private key alias under which to install the certificate. If a certificate
* with that alias already exists, it will be overwritten.
* @param requestAccess {@code true} to request that the calling app be granted access to the
@@ -2820,14 +2858,20 @@
* @return {@code true} if the keys were installed, {@code false} otherwise.
* @throws SecurityException if {@code admin} is not {@code null} and not a device or profile
* owner.
+ * @see android.security.KeyChain#getCertificateChain
*/
public boolean installKeyPair(@Nullable ComponentName admin, @NonNull PrivateKey privKey,
- @NonNull Certificate cert, @NonNull String alias, boolean requestAccess) {
+ @NonNull Certificate[] certs, @NonNull String alias, boolean requestAccess) {
try {
- final byte[] pemCert = Credentials.convertToPem(cert);
+ final byte[] pemCert = Credentials.convertToPem(certs[0]);
+ byte[] pemChain = null;
+ if (certs.length > 1) {
+ pemChain = Credentials.convertToPem(Arrays.copyOfRange(certs, 1, certs.length));
+ }
final byte[] pkcs8Key = KeyFactory.getInstance(privKey.getAlgorithm())
.getKeySpec(privKey, PKCS8EncodedKeySpec.class).getEncoded();
- return mService.installKeyPair(admin, pkcs8Key, pemCert, alias, requestAccess);
+ return mService.installKeyPair(admin, pkcs8Key, pemCert, pemChain, alias,
+ requestAccess);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
} catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
@@ -3736,24 +3780,22 @@
*
* @param admin The name of the admin component to check.
* @param info Device owner information which will be displayed instead of the user owner info.
- * @return Whether the device owner information has been set.
* @throws SecurityException if {@code admin} is not a device owner.
*/
- public boolean setDeviceOwnerLockScreenInfo(@NonNull ComponentName admin, String info) {
+ public void setDeviceOwnerLockScreenInfo(@NonNull ComponentName admin, CharSequence info) {
if (mService != null) {
try {
- return mService.setDeviceOwnerLockScreenInfo(admin, info);
+ mService.setDeviceOwnerLockScreenInfo(admin, info);
} catch (RemoteException re) {
throw re.rethrowFromSystemServer();
}
}
- return false;
}
/**
* @return The device owner information. If it is not set returns {@code null}.
*/
- public String getDeviceOwnerLockScreenInfo() {
+ public CharSequence getDeviceOwnerLockScreenInfo() {
if (mService != null) {
try {
return mService.getDeviceOwnerLockScreenInfo();
@@ -3803,13 +3845,17 @@
* @return {@code true} if the package is suspended or {@code false} if the package is not
* suspended, could not be found or an error occurred.
* @throws SecurityException if {@code admin} is not a device or profile owner.
+ * @throws NameNotFoundException if the package could not be found.
*/
- public boolean getPackageSuspended(@NonNull ComponentName admin, String packageName) {
+ public boolean isPackageSuspended(@NonNull ComponentName admin, String packageName)
+ throws NameNotFoundException {
if (mService != null) {
try {
- return mService.getPackageSuspended(admin, packageName);
+ return mService.isPackageSuspended(admin, packageName);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
+ } catch (IllegalArgumentException ex) {
+ throw new NameNotFoundException(packageName);
}
}
return false;
@@ -4881,15 +4927,30 @@
* @throws SecurityException if {@code admin} is not a device or profile owner.
*/
public Bundle getUserRestrictions(@NonNull ComponentName admin) {
- return getUserRestrictions(admin, myUserId());
- }
-
- /** @hide per-user version */
- public Bundle getUserRestrictions(@NonNull ComponentName admin, int userHandle) {
Bundle ret = null;
if (mService != null) {
try {
- ret = mService.getUserRestrictions(admin, userHandle);
+ ret = mService.getUserRestrictions(admin);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+ return ret == null ? new Bundle() : ret;
+ }
+
+ /**
+ * Called by the system to get the user restrictions for a user.
+ *
+ * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+ * @param userHandle user id the admin is running as.
+ *
+ * @hide
+ */
+ public Bundle getUserRestrictionsForUser(@NonNull ComponentName admin, int userHandle) {
+ Bundle ret = null;
+ if (mService != null) {
+ try {
+ ret = mService.getUserRestrictionsForUser(admin, userHandle);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -5590,10 +5651,9 @@
}
/**
- * @hide
* Return if this user is a managed profile of another user. An admin can become the profile
* owner of a managed profile with {@link #ACTION_PROVISION_MANAGED_PROFILE} and of a managed
- * user with {@link #ACTION_PROVISION_MANAGED_USER}.
+ * user with {@link #createAndManageUser}
* @param admin Which profile owner this request is associated with.
* @return if this user is a managed profile of another user.
*/
@@ -5897,7 +5957,7 @@
* <p>
* <strong> The device logs are retrieved from a RAM region which is not guaranteed to be
* corruption-free during power cycles, due to hardware variations and limitations. As a result,
- * this API is provided as best-effort and the returned logs may contain corrupted
+ * this API is provided as best-effort and the returned logs may be empty or contain corrupted
* data. </strong>
* <p>
* There must be only one user on the device, managed by the device owner. Otherwise a
@@ -5919,7 +5979,7 @@
/**
* Called by a profile owner of a managed profile to set the color used for customization. This
* color is used as background color of the confirm credentials screen for that user. The
- * default color is {@link android.graphics.Color#GRAY}.
+ * default color is teal (#00796B).
* <p>
* The confirm credentials screen can be created using
* {@link android.app.KeyguardManager#createConfirmDeviceCredentialIntent}.
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index aed220d..6ee56aa 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -135,18 +135,20 @@
void clearProfileOwner(in ComponentName who);
boolean hasUserSetupCompleted();
- boolean setDeviceOwnerLockScreenInfo(in ComponentName who, String deviceOwnerInfo);
- String getDeviceOwnerLockScreenInfo();
+ void setDeviceOwnerLockScreenInfo(in ComponentName who, CharSequence deviceOwnerInfo);
+ CharSequence getDeviceOwnerLockScreenInfo();
String[] setPackagesSuspended(in ComponentName admin, in String[] packageNames, boolean suspended);
- boolean getPackageSuspended(in ComponentName admin, String packageName);
+ boolean isPackageSuspended(in ComponentName admin, String packageName);
boolean installCaCert(in ComponentName admin, in byte[] certBuffer);
void uninstallCaCerts(in ComponentName admin, in String[] aliases);
void enforceCanManageCaCerts(in ComponentName admin);
+ boolean approveCaCert(in String alias, int userHandle, boolean approval);
+ boolean isCaCertApproved(in String alias, int userHandle);
boolean installKeyPair(in ComponentName who, in byte[] privKeyBuffer, in byte[] certBuffer,
- String alias, boolean requestAccess);
+ in byte[] certChainBuffer, String alias, boolean requestAccess);
boolean removeKeyPair(in ComponentName who, String alias);
void choosePrivateKeyAlias(int uid, in Uri uri, in String alias, IBinder aliasCallback);
@@ -169,7 +171,8 @@
ComponentName getRestrictionsProvider(int userHandle);
void setUserRestriction(in ComponentName who, in String key, boolean enable);
- Bundle getUserRestrictions(in ComponentName who, int userId);
+ Bundle getUserRestrictions(in ComponentName who);
+ Bundle getUserRestrictionsForUser(in ComponentName who, int userId);
void addCrossProfileIntentFilter(in ComponentName admin, in IntentFilter filter, int flags);
void clearCrossProfileIntentFilters(in ComponentName admin);
diff --git a/core/java/android/app/admin/SecurityLog.java b/core/java/android/app/admin/SecurityLog.java
index 001a81d..2858991 100644
--- a/core/java/android/app/admin/SecurityLog.java
+++ b/core/java/android/app/admin/SecurityLog.java
@@ -67,7 +67,7 @@
* information about the process encapsulated in an {@link Object} array, accessible via
* {@link SecurityEvent#getData()}:
* process name (String), exact start time (long), app Uid (integer), app Pid (integer),
- * seinfo tag (String), SHA-256 hash of the APK in hexadecimal (String)
+ * seinfo tag (String), SHA-256 hash of the base APK in hexadecimal (String)
*/
public static final int TAG_APP_PROCESS_START = SecurityLogTags.SECURITY_APP_PROCESS_START;
/**
diff --git a/core/java/android/bluetooth/BluetoothGatt.java b/core/java/android/bluetooth/BluetoothGatt.java
index 68442ea..b8a40dc 100644
--- a/core/java/android/bluetooth/BluetoothGatt.java
+++ b/core/java/android/bluetooth/BluetoothGatt.java
@@ -422,7 +422,7 @@
try {
mAuthRetry = true;
mService.writeDescriptor(mClientIf, address, handle,
- descriptor.getCharacteristic().getWriteType(),
+ BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT,
AUTHENTICATION_MITM, descriptor.getValue());
return;
} catch (RemoteException e) {
@@ -545,7 +545,6 @@
/*package*/ BluetoothGattCharacteristic getCharacteristicById(BluetoothDevice device, int instanceId) {
for(BluetoothGattService svc : mServices) {
for(BluetoothGattCharacteristic charac : svc.getCharacteristics()) {
- Log.w(TAG, "getCharacteristicById() comparing " + charac.getInstanceId() + " and " + instanceId);
if (charac.getInstanceId() == instanceId)
return charac;
}
@@ -944,7 +943,8 @@
try {
mService.writeDescriptor(mClientIf, device.getAddress(), descriptor.getInstanceId(),
- characteristic.getWriteType(), AUTHENTICATION_NONE, descriptor.getValue());
+ BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT, AUTHENTICATION_NONE,
+ descriptor.getValue());
} catch (RemoteException e) {
Log.e(TAG,"",e);
mDeviceBusy = false;
diff --git a/core/java/android/bluetooth/BluetoothGattCharacteristic.java b/core/java/android/bluetooth/BluetoothGattCharacteristic.java
index 7d698b3..01f82e6 100644
--- a/core/java/android/bluetooth/BluetoothGattCharacteristic.java
+++ b/core/java/android/bluetooth/BluetoothGattCharacteristic.java
@@ -284,6 +284,8 @@
out.writeInt(mInstance);
out.writeInt(mProperties);
out.writeInt(mPermissions);
+ out.writeInt(mKeySize);
+ out.writeInt(mWriteType);
out.writeTypedList(mDescriptors);
}
@@ -303,6 +305,8 @@
mInstance = in.readInt();
mProperties = in.readInt();
mPermissions = in.readInt();
+ mKeySize = in.readInt();
+ mWriteType = in.readInt();
mDescriptors = new ArrayList<BluetoothGattDescriptor>();
diff --git a/core/java/android/bluetooth/BluetoothManager.java b/core/java/android/bluetooth/BluetoothManager.java
index e355a1c..35437a1 100644
--- a/core/java/android/bluetooth/BluetoothManager.java
+++ b/core/java/android/bluetooth/BluetoothManager.java
@@ -144,7 +144,7 @@
}
/**
- *
+ *
* Get a list of devices that match any of the given connection
* states.
*
diff --git a/core/java/android/bluetooth/BluetoothPbapClient.java b/core/java/android/bluetooth/BluetoothPbapClient.java
index 736e55d..eab4c6f 100644
--- a/core/java/android/bluetooth/BluetoothPbapClient.java
+++ b/core/java/android/bluetooth/BluetoothPbapClient.java
@@ -40,7 +40,6 @@
"android.bluetooth.pbap.profile.action.CONNECTION_STATE_CHANGED";
private IBluetoothPbapClient mService;
- private BluetoothDevice mDevice;
private final Context mContext;
private ServiceListener mServiceListener;
private BluetoothAdapter mAdapter;
@@ -173,7 +172,6 @@
}
if (mService != null && isEnabled() && isValidDevice(device)) {
try {
- mDevice = device;
return mService.connect(device);
} catch (RemoteException e) {
Log.e(TAG, Log.getStackTraceString(new Throwable()));
@@ -193,13 +191,13 @@
* @return false on error,
* true otherwise
*/
- public boolean disconnect() {
+ public boolean disconnect(BluetoothDevice device) {
if (DBG) {
- log("disconnect(" + mDevice + ")");
+ log("disconnect(" + device + ")" + new Exception() );
}
- if (mService != null && isEnabled() && isValidDevice(mDevice)) {
+ if (mService != null && isEnabled() && isValidDevice(device)) {
try {
- mService.disconnect(mDevice);
+ mService.disconnect(device);
return true;
} catch (RemoteException e) {
Log.e(TAG, Log.getStackTraceString(new Throwable()));
@@ -328,4 +326,66 @@
}
return false;
}
+
+ /**
+ * Set priority of the profile
+ *
+ * <p> The device should already be paired.
+ * Priority can be one of {@link #PRIORITY_ON} or
+ * {@link #PRIORITY_OFF},
+ *
+ * @param device Paired bluetooth device
+ * @param priority
+ * @return true if priority is set, false on error
+ */
+ 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 {
+ return mService.setPriority(device, priority);
+ } catch (RemoteException e) {
+ Log.e(TAG, Log.getStackTraceString(new Throwable()));
+ return false;
+ }
+ }
+ if (mService == null) {
+ Log.w(TAG, "Proxy not attached to service");
+ }
+ return false;
+ }
+
+ /**
+ * Get the priority of the profile.
+ *
+ * <p> The priority can be any of:
+ * {@link #PRIORITY_AUTO_CONNECT}, {@link #PRIORITY_OFF},
+ * {@link #PRIORITY_ON}, {@link #PRIORITY_UNDEFINED}
+ *
+ * @param device Bluetooth device
+ * @return priority of the device
+ */
+ public int getPriority(BluetoothDevice device) {
+ if (VDBG) {
+ log("getPriority(" + device + ")");
+ }
+ if (mService != null && isEnabled() && isValidDevice(device)) {
+ try {
+ return mService.getPriority(device);
+ } catch (RemoteException e) {
+ Log.e(TAG, Log.getStackTraceString(new Throwable()));
+ return PRIORITY_OFF;
+ }
+ }
+ if (mService == null) {
+ Log.w(TAG, "Proxy not attached to service");
+ }
+ return PRIORITY_OFF;
+ }
}
diff --git a/core/java/android/bluetooth/IBluetoothPbapClient.aidl b/core/java/android/bluetooth/IBluetoothPbapClient.aidl
index b26ea29..6d4c5a6 100644
--- a/core/java/android/bluetooth/IBluetoothPbapClient.aidl
+++ b/core/java/android/bluetooth/IBluetoothPbapClient.aidl
@@ -29,4 +29,6 @@
List<BluetoothDevice> getConnectedDevices();
List<BluetoothDevice> getDevicesMatchingConnectionStates(in int[] states);
int getConnectionState(in BluetoothDevice device);
+ boolean setPriority(in BluetoothDevice device, int priority);
+ int getPriority(in BluetoothDevice device);
}
diff --git a/core/java/android/content/ContextWrapper.java b/core/java/android/content/ContextWrapper.java
index b2df207..087ac47 100644
--- a/core/java/android/content/ContextWrapper.java
+++ b/core/java/android/content/ContextWrapper.java
@@ -164,6 +164,7 @@
return mBase.getSharedPreferences(name, mode);
}
+ /** @removed */
@Override
public SharedPreferences getSharedPreferences(File file, int mode) {
return mBase.getSharedPreferences(file, mode);
@@ -201,6 +202,7 @@
return mBase.getFileStreamPath(name);
}
+ /** @removed */
@Override
public File getSharedPreferencesPath(String name) {
return mBase.getSharedPreferencesPath(name);
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 66e0ada..30f2c94 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -1581,14 +1581,6 @@
= "android.intent.extra.UNINSTALL_ALL_USERS";
/**
- * Specified when the uninstall confirmation dialog is not required to be shown.
- * Use with {@link #ACTION_UNINSTALL_PACKAGE}
- * @hide
- */
- public static final String EXTRA_SKIP_UNINSTALL_CONFIRMATION =
- "android.intent.extra.SKIP_UNINSTALL_CONFIRMATION";
-
- /**
* A string associated with a {@link #ACTION_UPGRADE_SETUP} activity
* describing the last run version of the platform that was setup.
* @hide
@@ -3064,15 +3056,29 @@
public static final String ACTION_MANAGED_PROFILE_UNLOCKED =
"android.intent.action.MANAGED_PROFILE_UNLOCKED";
+ /** @hide */
+ public static final String ACTION_MANAGED_PROFILE_AVAILABILITY_CHANGED =
+ "android.intent.action.MANAGED_PROFILE_AVAILABILITY_CHANGED";
+
/**
- * Broadcast sent to the primary user when an associated managed profile's availability has
- * changed. This includes when the user toggles the profile's quiet mode. Carries an extra
+ * Broadcast sent to the primary user when an associated managed profile has become available.
+ * Currently this includes when the user disables quiet mode for the profile. Carries an extra
* {@link #EXTRA_USER} that specifies the UserHandle of the profile. When quiet mode is changed,
* this broadcast will carry a boolean extra {@link #EXTRA_QUIET_MODE} indicating the new state
* of quiet mode. This is only sent to registered receivers, not manifest receivers.
*/
- public static final String ACTION_MANAGED_PROFILE_AVAILABILITY_CHANGED =
- "android.intent.action.MANAGED_PROFILE_AVAILABILITY_CHANGED";
+ public static final String ACTION_MANAGED_PROFILE_AVAILABLE =
+ "android.intent.action.MANAGED_PROFILE_AVAILABLE";
+
+ /**
+ * Broadcast sent to the primary user when an associated managed profile has become unavailable.
+ * Currently this includes when the user enables quiet mode for the profile. Carries an extra
+ * {@link #EXTRA_USER} that specifies the UserHandle of the profile. When quiet mode is changed,
+ * this broadcast will carry a boolean extra {@link #EXTRA_QUIET_MODE} indicating the new state
+ * of quiet mode. This is only sent to registered receivers, not manifest receivers.
+ */
+ public static final String ACTION_MANAGED_PROFILE_UNAVAILABLE =
+ "android.intent.action.MANAGED_PROFILE_UNAVAILABLE";
/**
* Sent when the user taps on the clock widget in the system's "quick settings" area.
@@ -4173,6 +4179,9 @@
/**
* Optional boolean extra indicating whether quiet mode has been switched on or off.
+ * When a profile goes into quiet mode, all apps in the profile are killed and the
+ * profile user is stopped. Widgets originating from the profile are masked, and app
+ * launcher icons are grayed out.
*/
public static final String EXTRA_QUIET_MODE = "android.intent.extra.QUIET_MODE";
diff --git a/core/java/android/content/IntentFilter.java b/core/java/android/content/IntentFilter.java
index 3a17e23..ed5dfa5 100644
--- a/core/java/android/content/IntentFilter.java
+++ b/core/java/android/content/IntentFilter.java
@@ -883,6 +883,15 @@
return true;
}
+ @Override
+ public boolean equals(Object obj) {
+ if (obj instanceof AuthorityEntry) {
+ final AuthorityEntry other = (AuthorityEntry)obj;
+ return match(other);
+ }
+ return false;
+ }
+
/**
* Determine whether this AuthorityEntry matches the given data Uri.
* <em>Note that this comparison is case-sensitive, unlike formal
@@ -917,7 +926,7 @@
}
return MATCH_CATEGORY_HOST;
}
- };
+ }
/**
* Add a new Intent data "scheme specific part" to match against. The filter must
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index e3fb161..6fce36b 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -316,6 +316,12 @@
int getApplicationEnabledSetting(in String packageName, int userId);
/**
+ * Logs process start information (including APK hash) to the security log.
+ */
+ void logAppProcessStartIfNeeded(String processName, int uid, String seinfo, String apkFile,
+ int pid);
+
+ /**
* As per {@link android.content.pm.PackageManager#flushPackageRestrictionsAsUser}.
*/
void flushPackageRestrictionsAsUser(in int userId);
@@ -431,10 +437,9 @@
void performFstrimIfNeeded();
/**
- * Ask the package manager to extract packages if needed, to save
- * the VM unzipping the APK in memory during launch.
+ * Ask the package manager to update packages if needed.
*/
- void extractPackagesIfNeeded();
+ void updatePackagesIfNeeded();
/**
* Notify the package manager that a package is going to be used.
diff --git a/core/java/android/content/pm/IShortcutService.aidl b/core/java/android/content/pm/IShortcutService.aidl
index 8f9dcfc..31d377b 100644
--- a/core/java/android/content/pm/IShortcutService.aidl
+++ b/core/java/android/content/pm/IShortcutService.aidl
@@ -47,4 +47,8 @@
int getIconMaxDimensions(String packageName, int userId);
void resetThrottling(); // system only API for developer opsions
+
+ byte[] getBackupPayload(int user);
+
+ void applyRestore(in byte[] payload, int user);
}
\ No newline at end of file
diff --git a/core/java/android/content/pm/LauncherActivityInfo.java b/core/java/android/content/pm/LauncherActivityInfo.java
index a5617b4..40e1a9f 100644
--- a/core/java/android/content/pm/LauncherActivityInfo.java
+++ b/core/java/android/content/pm/LauncherActivityInfo.java
@@ -103,53 +103,22 @@
* @return The drawable associated with the activity.
*/
public Drawable getIcon(int density) {
- final int iconRes = mResolveInfo.getIconResource();
- Drawable icon = getDrawableForDensity(iconRes, density);
- // Get the default density icon
- if (icon == null) {
- icon = mResolveInfo.loadIcon(mPm);
- }
- return icon;
- }
-
- /**
- * Returns the icon for this activity, without any badging for the profile.
- * This function can get the icon no matter the icon needs to be badged or not.
- * @param density The preferred density of the icon, zero for default density. Use
- * density DPI values from {@link DisplayMetrics}.
- * @see #getBadgedIcon(int)
- * @see DisplayMetrics
- * @return The drawable associated with the activity.
- */
- private Drawable getOriginalIcon(int density) {
final int iconRes = mResolveInfo.getIconResourceInternal();
- Drawable icon = getDrawableForDensity(iconRes, density);
- // Get the default density icon
- if (icon == null) {
- icon = mResolveInfo.loadIcon(mPm);
- }
- return icon;
- }
-
- /**
- * Returns the drawable for this activity, without any badging for the profile.
- * @param iconRes id of the drawable.
- * @param density The preferred density of the icon, zero for default density. Use
- * density DPI values from {@link DisplayMetrics}.
- * @see DisplayMetrics
- * @return The drawable associated with the resource id.
- */
- private Drawable getDrawableForDensity(int iconRes, int density) {
+ Drawable icon = null;
// Get the preferred density icon from the app's resources
if (density != 0 && iconRes != 0) {
try {
final Resources resources
= mPm.getResourcesForApplication(mActivityInfo.applicationInfo);
- return resources.getDrawableForDensity(iconRes, density);
+ icon = resources.getDrawableForDensity(iconRes, density);
} catch (NameNotFoundException | Resources.NotFoundException exc) {
}
}
- return null;
+ // Get the default density icon
+ if (icon == null) {
+ icon = mResolveInfo.loadIcon(mPm);
+ }
+ return icon;
}
/**
@@ -201,7 +170,7 @@
* @return A badged icon for the activity.
*/
public Drawable getBadgedIcon(int density) {
- Drawable originalIcon = getOriginalIcon(density);
+ Drawable originalIcon = getIcon(density);
if (originalIcon instanceof BitmapDrawable) {
return mPm.getUserBadgedIcon(originalIcon, mUser);
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index e89cbd7..39bc783 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -130,6 +130,7 @@
MATCH_DISABLED_COMPONENTS,
MATCH_DISABLED_UNTIL_USED_COMPONENTS,
MATCH_SYSTEM_ONLY,
+ MATCH_FACTORY_ONLY,
MATCH_DEBUG_TRIAGED_MISSING,
})
@Retention(RetentionPolicy.SOURCE)
@@ -415,6 +416,13 @@
public static final int MATCH_SYSTEM_ONLY = 0x00100000;
/**
+ * Internal {@link PackageInfo} flag: include only components on the system image.
+ * This will not return information on any unbundled update to system components.
+ * @hide
+ */
+ public static final int MATCH_FACTORY_ONLY = 0x00200000;
+
+ /**
* Internal flag used to indicate that a system component has done their
* homework and verified that they correctly handle packages and components
* that come and go over time. In particular:
diff --git a/core/java/android/content/pm/PermissionInfo.java b/core/java/android/content/pm/PermissionInfo.java
index 984a960..65e0b92 100644
--- a/core/java/android/content/pm/PermissionInfo.java
+++ b/core/java/android/content/pm/PermissionInfo.java
@@ -113,6 +113,13 @@
public static final int PROTECTION_FLAG_PREINSTALLED = 0x400;
/**
+ * Additional flag for {@link #protectionLevel}, corresponding
+ * to the <code>setup</code> value of
+ * {@link android.R.attr#protectionLevel}.
+ */
+ public static final int PROTECTION_FLAG_SETUP = 0x800;
+
+ /**
* Mask for {@link #protectionLevel}: the basic protection type.
*/
public static final int PROTECTION_MASK_BASE = 0xf;
@@ -226,6 +233,9 @@
if ((level&PermissionInfo.PROTECTION_FLAG_PREINSTALLED) != 0) {
protLevel += "|preinstalled";
}
+ if ((level&PermissionInfo.PROTECTION_FLAG_SETUP) != 0) {
+ protLevel += "|setup";
+ }
return protLevel;
}
diff --git a/core/java/android/content/pm/ShortcutInfo.java b/core/java/android/content/pm/ShortcutInfo.java
index ae75e3f..1812575a 100644
--- a/core/java/android/content/pm/ShortcutInfo.java
+++ b/core/java/android/content/pm/ShortcutInfo.java
@@ -34,20 +34,22 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+// TODO Enhance javadoc
/**
- * TODO Enhance javadoc
*
- * Represents a shortcut form an application.
+ * Represents a shortcut from an application.
*
- * Notes...
- * - If an {@link Icon} is of a resource, then we'll just persist the package name and resource ID.
+ * <p>Notes about icons:
+ * <ul>
+ * <li>If an {@link Icon} is a resource, the system keeps the package name and the resource ID.
+ * Otherwise, the bitmap is fetched when it's registered to ShortcutManager,
+ * then shrunk if necessary, and persisted.
+ * <li>The system disallows byte[] icons, because they can easily go over the binder size limit.
+ * </ul>
*
- * Otherwise, the bitmap will be fetched when it's registered to ShortcutManager, then *shrunk*
- * if necessary, and persisted.
- *
- * We will disallow byte[] icons, because they can easily go over binder size limit.
+ * @see {@link ShortcutManager}.
*/
-public class ShortcutInfo implements Parcelable {
+public final class ShortcutInfo implements Parcelable {
/* @hide */
public static final int FLAG_DYNAMIC = 1 << 0;
@@ -118,6 +120,9 @@
@NonNull
private String mTitle;
+ @Nullable
+ private String mText;
+
/**
* Intent *with extras removed*.
*/
@@ -157,6 +162,7 @@
mActivityComponent = b.mActivityComponent;
mIcon = b.mIcon;
mTitle = b.mTitle;
+ mText = b.mText;
mIntent = b.mIntent;
if (mIntent != null) {
final Bundle intentExtras = mIntent.getExtras();
@@ -176,6 +182,7 @@
* @hide
*/
public void enforceMandatoryFields() {
+ Preconditions.checkStringNotEmpty(mId, "Shortcut ID must be provided");
Preconditions.checkStringNotEmpty(mTitle, "Shortcut title must be provided");
Preconditions.checkNotNull(mIntent, "Shortcut Intent must be provided");
}
@@ -195,16 +202,17 @@
if ((cloneFlags & CLONE_REMOVE_ICON) == 0) {
mIcon = source.mIcon;
mBitmapPath = source.mBitmapPath;
+ mIconResourceId = source.mIconResourceId;
}
mTitle = source.mTitle;
+ mText = source.mText;
if ((cloneFlags & CLONE_REMOVE_INTENT) == 0) {
mIntent = source.mIntent;
mIntentPersistableExtras = source.mIntentPersistableExtras;
}
mWeight = source.mWeight;
mExtras = source.mExtras;
- mIconResourceId = source.mIconResourceId;
} else {
// Set this bit.
mFlags |= FLAG_KEY_FIELDS_ONLY;
@@ -244,6 +252,9 @@
if (source.mTitle != null) {
mTitle = source.mTitle;
}
+ if (source.mText != null) {
+ mText = source.mText;
+ }
if (source.mIntent != null) {
mIntent = source.mIntent;
mIntentPersistableExtras = source.mIntentPersistableExtras;
@@ -305,6 +316,8 @@
private String mTitle;
+ private String mText;
+
private Intent mIntent;
private int mWeight;
@@ -360,6 +373,9 @@
/**
* Sets the title of a shortcut. This is a mandatory field.
+ *
+ * <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 setTitle(@NonNull String title) {
@@ -368,6 +384,18 @@
}
/**
+ * Sets the text of a shortcut. This is an optional field.
+ *
+ * <p>This field is intended to be more descriptive than the shortcut title.
+ * The recommend max length is 25 characters.
+ */
+ @NonNull
+ public Builder setText(@NonNull String text) {
+ mText = Preconditions.checkStringNotEmpty(text, "text");
+ return this;
+ }
+
+ /**
* Sets the intent of a shortcut. This is a mandatory field. The extras must only contain
* persistable information. (See {@link PersistableBundle}).
*/
@@ -457,6 +485,14 @@
}
/**
+ * Return the shortcut text.
+ */
+ @Nullable
+ public String getText() {
+ return mText;
+ }
+
+ /**
* Return the intent.
*
* <p>All shortcuts must have an intent, but this method will return null when
@@ -630,6 +666,7 @@
mActivityComponent = source.readParcelable(cl);
mIcon = source.readParcelable(cl);
mTitle = source.readString();
+ mText = source.readString();
mIntent = source.readParcelable(cl);
mIntentPersistableExtras = source.readParcelable(cl);
mWeight = source.readInt();
@@ -647,6 +684,7 @@
dest.writeParcelable(mActivityComponent, flags);
dest.writeParcelable(mIcon, flags);
dest.writeString(mTitle);
+ dest.writeString(mText);
dest.writeParcelable(mIntent, flags);
dest.writeParcelable(mIntentPersistableExtras, flags);
dest.writeInt(mWeight);
@@ -708,6 +746,9 @@
sb.append(", title=");
sb.append(secure ? "***" : mTitle);
+ sb.append(", text=");
+ sb.append(secure ? "***" : mText);
+
sb.append(", icon=");
sb.append(mIcon);
@@ -744,7 +785,8 @@
/** @hide */
public ShortcutInfo(String id, String packageName, ComponentName activityComponent,
- Icon icon, String title, Intent intent, PersistableBundle intentPersistableExtras,
+ Icon icon, String title, String text, Intent intent,
+ PersistableBundle intentPersistableExtras,
int weight, PersistableBundle extras, long lastChangedTimestamp,
int flags, int iconResId, String bitmapPath) {
mId = id;
@@ -752,6 +794,7 @@
mActivityComponent = activityComponent;
mIcon = icon;
mTitle = title;
+ mText = text;
mIntent = intent;
mIntentPersistableExtras = intentPersistableExtras;
mWeight = weight;
diff --git a/core/java/android/content/pm/ShortcutManager.java b/core/java/android/content/pm/ShortcutManager.java
index b247f65..e4a98b5 100644
--- a/core/java/android/content/pm/ShortcutManager.java
+++ b/core/java/android/content/pm/ShortcutManager.java
@@ -19,15 +19,13 @@
import android.content.Context;
import android.os.RemoteException;
import android.os.UserHandle;
-import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
import java.util.List;
+// TODO Enhance javadoc
/**
- * TODO Enhance javadoc
- *
* {@link ShortcutManager} manages shortcuts created by applications.
*
* <h3>Dynamic shortcuts and pinned shortcuts</h3>
@@ -66,15 +64,18 @@
* {@link #getRemainingCallCount()} times until the rate-limiting counter is reset,
* which happens at a certain time every day.
*
- * <p>An applications can use {@link #getRateLimitResetTime()} to get the next reset time.
+ * <p>An application can use {@link #getRateLimitResetTime()} to get the next reset time.
+ *
+ * <p>For testing purposes, use "Developer Options" (found in the Settings menu) to reset the
+ * internal rate-limiting counter. Automated tests can use the following ADB shell command to
+ * achieve the same effect:</p>
+ * <pre>adb shell cmd shortcut reset-throttling</pre>
*
* <h3>Backup and Restore</h3>
*
* Shortcuts will be backed up and restored across devices. This means all information, including
* IDs, must be meaningful on a different device.
*
- * TODO: Define a Broadcast to let apps update shortcuts on a restored device.
- *
* <h3>APIs for launcher</h3>
*
* Launcher applications should use {@link LauncherApps} to get shortcuts that are published from
diff --git a/core/java/android/content/pm/ShortcutServiceInternal.java b/core/java/android/content/pm/ShortcutServiceInternal.java
index 4255582..d57f2e6e 100644
--- a/core/java/android/content/pm/ShortcutServiceInternal.java
+++ b/core/java/android/content/pm/ShortcutServiceInternal.java
@@ -40,28 +40,37 @@
}
public abstract List<ShortcutInfo>
- getShortcuts(@NonNull String callingPackage, long changedSince,
+ getShortcuts(int launcherUserId,
+ @NonNull String callingPackage, long changedSince,
@Nullable String packageName, @Nullable ComponentName componentName,
@ShortcutQuery.QueryFlags int flags,
int userId);
public abstract List<ShortcutInfo>
- getShortcutInfo(@NonNull String callingPackage,
+ getShortcutInfo(int launcherUserId, @NonNull String callingPackage,
@NonNull String packageName, @Nullable List<String> ids, int userId);
- public abstract void pinShortcuts(@NonNull String callingPackage, @NonNull String packageName,
+
+ public abstract boolean
+ isPinnedByCaller(int launcherUserId, @NonNull String callingPackage,
+ @NonNull String packageName, @NonNull String id, int userId);
+
+ public abstract void pinShortcuts(int launcherUserId,
+ @NonNull String callingPackage, @NonNull String packageName,
@NonNull List<String> shortcutIds, int userId);
- public abstract Intent createShortcutIntent(@NonNull String callingPackage,
+ public abstract Intent createShortcutIntent(int launcherUserId, @NonNull String callingPackage,
@NonNull String packageName, @NonNull String shortcutId, int userId);
public abstract void addListener(@NonNull ShortcutChangeListener listener);
- public abstract int getShortcutIconResId(@NonNull String callingPackage,
+ public abstract int getShortcutIconResId(int launcherUserId, @NonNull String callingPackage,
@NonNull ShortcutInfo shortcut, int userId);
- public abstract ParcelFileDescriptor getShortcutIconFd(@NonNull String callingPackage,
+ public abstract ParcelFileDescriptor getShortcutIconFd(int launcherUserId,
+ @NonNull String callingPackage,
@NonNull ShortcutInfo shortcut, int userId);
- public abstract boolean hasShortcutHostPermission(@NonNull String callingPackage, int userId);
+ public abstract boolean hasShortcutHostPermission(int launcherUserId,
+ @NonNull String callingPackage);
}
diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java
index 387fda7..93fe73b 100644
--- a/core/java/android/content/res/Resources.java
+++ b/core/java/android/content/res/Resources.java
@@ -714,12 +714,11 @@
* the resource ID passed here is an alias to another Drawable resource.
* This means that if the density configuration of the alias resource
* is different than the actual resource, the density of the returned
- * Drawable would be incorrect, resulting in bad scaling. To work
- * around this, you can instead retrieve the Drawable through
- * {@link TypedArray#getDrawable TypedArray.getDrawable}. Use
- * {@link android.content.Context#obtainStyledAttributes(int[])
- * Context.obtainStyledAttributes} with
- * an array containing the resource ID of interest to create the TypedArray.</p>
+ * Drawable would be incorrect, resulting in bad scaling. To work
+ * around this, you can instead manually resolve the aliased reference
+ * by using {@link #getValue(int, TypedValue, boolean)} and passing
+ * {@code true} for {@code resolveRefs}. The resulting
+ * {@link TypedValue#resourceId} value may be passed to this method.</p>
*
* <p class="note"><strong>Note:</strong> To obtain a themed drawable, use
* {@link android.content.Context#getDrawable(int) Context.getDrawable(int)}
diff --git a/core/java/android/hardware/Camera.java b/core/java/android/hardware/Camera.java
index 3dbe437..acf0677 100644
--- a/core/java/android/hardware/Camera.java
+++ b/core/java/android/hardware/Camera.java
@@ -76,7 +76,7 @@
* <li>If necessary, modify the returned {@link Camera.Parameters} object and call
* {@link #setParameters(Camera.Parameters)}.
*
- * <li>If desired, call {@link #setDisplayOrientation(int)}.
+ * <li>Call {@link #setDisplayOrientation(int)} to ensure correct orientation of preview.
*
* <li><b>Important</b>: Pass a fully initialized {@link SurfaceHolder} to
* {@link #setPreviewDisplay(SurfaceHolder)}. Without a surface, the camera
@@ -1511,9 +1511,15 @@
* <p>Starting from API level 14, this method can be called when preview is
* active.
*
+ * <p><b>Note: </b>Before API level 24, the default value for orientation is 0. Starting in
+ * API level 24, the default orientation will be such that applications in forced-landscape mode
+ * will have correct preview orientation, which may be either a default of 0 or
+ * 180. Applications that operate in portrait mode or allow for changing orientation must still
+ * call this method after each orientation change to ensure correct preview display in all
+ * cases.</p>
+ *
* @param degrees the angle that the picture will be rotated clockwise.
- * Valid values are 0, 90, 180, and 270. The starting
- * position is 0 (landscape).
+ * Valid values are 0, 90, 180, and 270.
* @see #setPreviewDisplay(SurfaceHolder)
*/
public native final void setDisplayOrientation(int degrees);
diff --git a/core/java/android/hardware/Sensor.java b/core/java/android/hardware/Sensor.java
index 63ee8d2..cc82eb6 100644
--- a/core/java/android/hardware/Sensor.java
+++ b/core/java/android/hardware/Sensor.java
@@ -186,7 +186,7 @@
* @see #TYPE_LINEAR_ACCELERATION
*/
public static final String STRING_TYPE_LINEAR_ACCELERATION =
- "android.sensor.linear_acceleration";
+ "android.sensor.linear_acceleration";
/**
* A constant describing a rotation vector sensor type.
@@ -229,7 +229,7 @@
* @see #TYPE_AMBIENT_TEMPERATURE
*/
public static final String STRING_TYPE_AMBIENT_TEMPERATURE =
- "android.sensor.ambient_temperature";
+ "android.sensor.ambient_temperature";
/**
* A constant describing an uncalibrated magnetic field sensor type.
@@ -254,7 +254,7 @@
* @see #TYPE_MAGNETIC_FIELD_UNCALIBRATED
*/
public static final String STRING_TYPE_MAGNETIC_FIELD_UNCALIBRATED =
- "android.sensor.magnetic_field_uncalibrated";
+ "android.sensor.magnetic_field_uncalibrated";
/**
* A constant describing an uncalibrated rotation vector sensor type.
@@ -280,7 +280,7 @@
* @see #TYPE_GAME_ROTATION_VECTOR
*/
public static final String STRING_TYPE_GAME_ROTATION_VECTOR =
- "android.sensor.game_rotation_vector";
+ "android.sensor.game_rotation_vector";
/**
* A constant describing an uncalibrated gyroscope sensor type.
@@ -302,7 +302,7 @@
* @see #TYPE_GYROSCOPE_UNCALIBRATED
*/
public static final String STRING_TYPE_GYROSCOPE_UNCALIBRATED =
- "android.sensor.gyroscope_uncalibrated";
+ "android.sensor.gyroscope_uncalibrated";
/**
* A constant describing a significant motion trigger sensor.
@@ -324,7 +324,7 @@
* @see #TYPE_SIGNIFICANT_MOTION
*/
public static final String STRING_TYPE_SIGNIFICANT_MOTION =
- "android.sensor.significant_motion";
+ "android.sensor.significant_motion";
/**
* A constant describing a step detector sensor.
@@ -391,7 +391,7 @@
* @see #TYPE_GEOMAGNETIC_ROTATION_VECTOR
*/
public static final String STRING_TYPE_GEOMAGNETIC_ROTATION_VECTOR =
- "android.sensor.geomagnetic_rotation_vector";
+ "android.sensor.geomagnetic_rotation_vector";
/**
* A constant describing a heart rate monitor.
@@ -431,7 +431,7 @@
* A constant string describing a wake up tilt detector sensor type.
*
* @hide
- * @see #TYPE_WAKE_UP_TILT_DETECTOR
+ * @see #TYPE_TILT_DETECTOR
*/
public static final String SENSOR_STRING_TYPE_TILT_DETECTOR =
"android.sensor.tilt_detector";
@@ -495,7 +495,7 @@
*/
public static final String STRING_TYPE_GLANCE_GESTURE = "android.sensor.glance_gesture";
- /**
+ /**
* A constant describing a pick up sensor.
*
* A sensor of this type triggers when the device is picked up regardless of wherever it was
@@ -514,7 +514,7 @@
*/
public static final String STRING_TYPE_PICK_UP_GESTURE = "android.sensor.pick_up_gesture";
- /**
+ /**
* A constant describing a wrist tilt gesture sensor.
*
* A sensor of this type triggers when the device face is tilted towards the user.
@@ -553,7 +553,7 @@
*/
public static final String STRING_TYPE_DEVICE_ORIENTATION = "android.sensor.device_orientation";
- /**
+ /**
* A constant describing a pose sensor with 6 degrees of freedom.
*
* Similar to {@link #TYPE_ROTATION_VECTOR}, with additional delta
@@ -578,7 +578,7 @@
*/
public static final String STRING_TYPE_POSE_6DOF = "android.sensor.pose_6dof";
- /**
+ /**
* A constant describing a stationary detect sensor.
*
* See {@link android.hardware.SensorEvent#values SensorEvent.values} for more details.
@@ -593,7 +593,7 @@
*/
public static final String STRING_TYPE_STATIONARY_DETECT = "android.sensor.stationary_detect";
- /**
+ /**
* A constant describing a motion detect sensor.
*
* See {@link android.hardware.SensorEvent#values SensorEvent.values} for more details.
@@ -608,7 +608,7 @@
*/
public static final String STRING_TYPE_MOTION_DETECT = "android.sensor.motion_detect";
- /**
+ /**
* A constant describing a motion detect sensor.
*
* See {@link android.hardware.SensorEvent#values SensorEvent.values} for more details.
@@ -706,6 +706,14 @@
private static final int DATA_INJECTION_MASK = 0x10;
private static final int DATA_INJECTION_SHIFT = 4;
+ // MASK for dynamic sensor (sensor that added during runtime), bit 6.
+ private static final int DYNAMIC_SENSOR_MASK = 0x20;
+ private static final int DYNAMIC_SENSOR_SHIFT = 5;
+
+ // MASK for indication bit of sensor additional information support (bit 7).
+ private static final int ADDITIONAL_INFO_MASK = 0x40;
+ private static final int ADDITIONAL_INFO_SHIFT = 6;
+
// TODO(): The following arrays are fragile and error-prone. This needs to be refactored.
// Note: This needs to be updated, whenever a new sensor is added.
@@ -887,13 +895,37 @@
}
/**
- * @return The type of this sensor as a string.
+ * @return The UUID of the sensor. If the sensor does not support UUID, the returned value will
+ * be an all zero UUID; if the sensor's combination of type and name is guaranteed to be unique
+ * in system, the return value will be an all "F" UUID.
+ *
+ * @hide
*/
+ @SystemApi
public UUID getUuid() {
return mUuid;
}
/**
+ * @return The unique id of sensor. Return value of 0 means this sensor does not support UUID;
+ * return value of -1 means this sensor can be uniquely identified in system by combination of
+ * its type and name.
+ */
+ public int getId() {
+ if (mUuid == ALL_0_UUID) {
+ return 0;
+ } else if (mUuid == ALL_F_UUID) {
+ return -1;
+ } else {
+ int id = Math.abs(mUuid.hashCode()) + 1;
+ if (id <= 0) { // catch corner case when hash is Integer.MIN_VALUE and Integer.MAX_VALUE
+ id = 1;
+ }
+ return id;
+ }
+ }
+
+ /**
* @hide
* @return The permission required to access this sensor. If empty, no permission is required.
*/
@@ -961,6 +993,26 @@
}
/**
+ * Returns true if the sensor is a dynamic sensor.
+ *
+ * @return <code>true</code> if the sensor is a dynamic sensor (sensor added at runtime).
+ * @see SensorManager.DynamicSensorCallback
+ */
+ public boolean isDynamicSensor() {
+ return (mFlags & DYNAMIC_SENSOR_MASK) != 0;
+ }
+
+ /**
+ * Returns true if the sensor supports sensor additional information API
+ *
+ * @return <code>true</code> if the sensor supports sensor additional information API
+ * @see SensorAdditionalInfo
+ */
+ public boolean isAdditionalInfoSupported() {
+ return (mFlags & ADDITIONAL_INFO_MASK) != 0;
+ }
+
+ /**
* Returns true if the sensor supports data injection when the
* HAL is set to data injection mode.
*
@@ -986,6 +1038,10 @@
+ ", power=" + mPower + ", minDelay=" + mMinDelay + "}";
}
+ //special UUID hash constant
+ private final static UUID ALL_0_UUID = new UUID(0,0);
+ private final static UUID ALL_F_UUID = new UUID(~0L, ~0L);
+
/**
* Sets the Type associated with the sensor.
* NOTE: to be used only by native bindings in SensorManager.
diff --git a/core/java/android/hardware/SensorAdditionalInfo.java b/core/java/android/hardware/SensorAdditionalInfo.java
index 8e5b8a3..572a287 100644
--- a/core/java/android/hardware/SensorAdditionalInfo.java
+++ b/core/java/android/hardware/SensorAdditionalInfo.java
@@ -27,7 +27,7 @@
* android.hardware.SensorEventCallback#onSensorAdditionalInfo onSensorAdditionalInfo}.
*
* @see SensorManager
- * @see SensorEventListener3
+ * @see SensorEventCallback
* @see Sensor
*
*/
@@ -106,7 +106,7 @@
* such as accelerometer, gyro, etc.
*
* Payload:
- * floatValues[0..11]: First 3 rows of a homogenous matrix in row major order that captures
+ * floatValues[0..11]: First 3 rows of a homogeneous matrix in row major order that captures
* any linear transformation, including rotation, scaling, shear, shift.
*/
public static final int TYPE_VEC3_CALIBRATION = 0x10002;
diff --git a/core/java/android/hardware/SensorEvent.java b/core/java/android/hardware/SensorEvent.java
index 35c96f7..0d96b8e 100644
--- a/core/java/android/hardware/SensorEvent.java
+++ b/core/java/android/hardware/SensorEvent.java
@@ -18,7 +18,7 @@
/**
* This class represents a {@link android.hardware.Sensor Sensor} event and
- * holds informations such as the sensor's type, the time-stamp, accuracy and of
+ * holds information such as the sensor's type, the time-stamp, accuracy and of
* course the sensor's {@link SensorEvent#values data}.
*
* <p>
@@ -163,7 +163,7 @@
* </ul>
* <p>
* Typically the output of the gyroscope is integrated over time to
- * calculate a rotation describing the change of angles over the timestep,
+ * calculate a rotation describing the change of angles over the time step,
* for example:
* </p>
*
@@ -173,7 +173,7 @@
* private float timestamp;
*
* public void onSensorChanged(SensorEvent event) {
- * // This timestep's delta rotation to be multiplied by the current rotation
+ * // This time step's delta rotation to be multiplied by the current rotation
* // after computing it from the gyro sample data.
* if (timestamp != 0) {
* final float dT = (event.timestamp - timestamp) * NS2S;
@@ -192,8 +192,8 @@
* axisZ /= omegaMagnitude;
* }
*
- * // Integrate around this axis with the angular speed by the timestep
- * // in order to get a delta rotation from this sample over the timestep
+ * // Integrate around this axis with the angular speed by the time step
+ * // in order to get a delta rotation from this sample over the time step
* // We will convert this axis-angle representation of the delta rotation
* // into a quaternion before turning it into the rotation matrix.
* float thetaOverTwo = omegaMagnitude * dT / 2.0f;
@@ -433,9 +433,9 @@
* Each field is a component of the estimated hard iron calibration.
* The values are in micro-Tesla (uT).
* </p>
- * <p> Hard iron - These distortions arise due to the magnetized iron, steel or permanenet
+ * <p> Hard iron - These distortions arise due to the magnetized iron, steel or permanent
* magnets on the device.
- * Soft iron - These distortions arise due to the interaction with the earth's magentic
+ * Soft iron - These distortions arise due to the interaction with the earth's magnetic
* field.
* </p>
* <h4> {@link android.hardware.Sensor#TYPE_GAME_ROTATION_VECTOR}:</h4>
@@ -508,14 +508,14 @@
*
*
* <ul>
- * <li> values[0]: x*sin(θ/2) </li>
- * <li> values[1]: y*sin(θ/2) </li>
- * <li> values[2]: z*sin(θ/2) </li>
- * <li> values[3]: cos(θ/2) </li>
+ * <li> values[0]: x*sin(θ/2) </li>
+ * <li> values[1]: y*sin(θ/2) </li>
+ * <li> values[2]: z*sin(θ/2) </li>
+ * <li> values[3]: cos(θ/2) </li>
*
*
* <li> values[4]: Translation along x axis from an arbitrary origin. </li>
- * li> values[5]: Translation along y axis from an arbitrary origin. </li>
+ * <li> values[5]: Translation along y axis from an arbitrary origin. </li>
* <li> values[6]: Translation along z axis from an arbitrary origin. </li>
*
* <li> values[7]: Delta quaternion rotation x*sin(θ/2) </li>
diff --git a/core/java/android/hardware/SensorManager.java b/core/java/android/hardware/SensorManager.java
index 5684aa5..a20307a 100644
--- a/core/java/android/hardware/SensorManager.java
+++ b/core/java/android/hardware/SensorManager.java
@@ -884,7 +884,7 @@
* Used for receiving notifications from the SensorManager when dynamic sensors are connected or
* disconnected.
*/
- public static abstract class DynamicSensorConnectionCallback {
+ public static abstract class DynamicSensorCallback {
/**
* Called when there is a dynamic sensor being connected to the system.
*
@@ -902,62 +902,73 @@
/**
- * Add a {@link android.hardware.SensorManager.DynamicSensorConnectionCallback
- * DynamicSensorConnectionCallback} to receive dynamic sensor connection callbacks. Repeat
+ * Add a {@link android.hardware.SensorManager.DynamicSensorCallback
+ * DynamicSensorCallback} to receive dynamic sensor connection callbacks. Repeat
* registration with the already registered callback object will have no additional effect.
*
* @param callback An object that implements the
- * {@link android.hardware.SensorManager.DynamicSensorConnectionCallback
- * DynamicSensorConnectionCallback}
+ * {@link android.hardware.SensorManager.DynamicSensorCallback
+ * DynamicSensorCallback}
* interface for receiving callbacks.
- * @see #addDynamicSensorCallback(DynamicSensorConnectionCallback, Handler)
+ * @see #addDynamicSensorCallback(DynamicSensorCallback, Handler)
*
* @throws IllegalArgumentException when callback is null.
*/
- public void registerDynamicSensorCallback(DynamicSensorConnectionCallback callback) {
+ public void registerDynamicSensorCallback(DynamicSensorCallback callback) {
registerDynamicSensorCallback(callback, null);
}
/**
- * Add a {@link android.hardware.SensorManager.DynamicSensorConnectionCallback
- * DynamicSensorConnectionCallback} to receive dynamic sensor connection callbacks. Repeat
+ * Add a {@link android.hardware.SensorManager.DynamicSensorCallback
+ * DynamicSensorCallback} to receive dynamic sensor connection callbacks. Repeat
* registration with the already registered callback object will have no additional effect.
*
* @param callback An object that implements the
- * {@link android.hardware.SensorManager.DynamicSensorConnectionCallback
- * DynamicSensorConnectionCallback} interface for receiving callbacks.
+ * {@link android.hardware.SensorManager.DynamicSensorCallback
+ * DynamicSensorCallback} interface for receiving callbacks.
* @param handler The {@link android.os.Handler Handler} the {@link
- * android.hardware.SensorManager.DynamicSensorConnectionCallback
+ * android.hardware.SensorManager.DynamicSensorCallback
* sensor connection events} will be delivered to.
*
* @throws IllegalArgumentException when callback is null.
*/
public void registerDynamicSensorCallback(
- DynamicSensorConnectionCallback callback, Handler handler) {
+ DynamicSensorCallback callback, Handler handler) {
registerDynamicSensorCallbackImpl(callback, handler);
}
/**
- * Remove a {@link android.hardware.SensorManager.DynamicSensorConnectionCallback
- * DynamicSensorConnectionCallback} to stop sending dynamic sensor connection events to that
+ * Remove a {@link android.hardware.SensorManager.DynamicSensorCallback
+ * DynamicSensorCallback} to stop sending dynamic sensor connection events to that
* callback.
*
* @param callback An object that implements the
- * {@link android.hardware.SensorManager.DynamicSensorConnectionCallback
- * DynamicSensorConnectionCallback}
+ * {@link android.hardware.SensorManager.DynamicSensorCallback
+ * DynamicSensorCallback}
* interface for receiving callbacks.
*/
- public void unregisterDynamicSensorCallback(DynamicSensorConnectionCallback callback) {
+ public void unregisterDynamicSensorCallback(DynamicSensorCallback callback) {
unregisterDynamicSensorCallbackImpl(callback);
}
+ /**
+ * Tell if dynamic sensor discovery feature is supported by system.
+ *
+ * @return <code>true</code> if dynamic sensor discovery is supported, <code>false</code>
+ * otherwise.
+ */
+ public boolean isDynamicSensorDiscoverySupported() {
+ List<Sensor> sensors = getSensorList(Sensor.TYPE_DYNAMIC_SENSOR_META);
+ return sensors.size() > 0;
+ }
+
/** @hide */
protected abstract void registerDynamicSensorCallbackImpl(
- DynamicSensorConnectionCallback callback, Handler handler);
+ DynamicSensorCallback callback, Handler handler);
/** @hide */
protected abstract void unregisterDynamicSensorCallbackImpl(
- DynamicSensorConnectionCallback callback);
+ DynamicSensorCallback callback);
/**
* <p>
diff --git a/core/java/android/hardware/SystemSensorManager.java b/core/java/android/hardware/SystemSensorManager.java
index b75e653..259ca03 100644
--- a/core/java/android/hardware/SystemSensorManager.java
+++ b/core/java/android/hardware/SystemSensorManager.java
@@ -1,4 +1,4 @@
- /*
+/*
* Copyright (C) 2012 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -31,12 +31,15 @@
import android.util.SparseIntArray;
import dalvik.system.CloseGuard;
+import com.android.internal.annotations.GuardedBy;
+
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+
/**
* Sensor manager implementation that communicates with the built-in
* system sensors.
@@ -55,7 +58,9 @@
private static native boolean nativeIsDataInjectionEnabled(long nativeInstance);
private static final Object sLock = new Object();
- private static boolean sSensorModuleInitialized = false;
+ @GuardedBy("sLock")
+ private static boolean sNativeClassInited = false;
+ @GuardedBy("sLock")
private static InjectEventQueue sInjectEventQueue = null;
private final ArrayList<Sensor> mFullSensorsList = new ArrayList<>();
@@ -71,7 +76,7 @@
new HashMap<TriggerEventListener, TriggerEventQueue>();
// Dynamic Sensor callbacks
- private HashMap<DynamicSensorConnectionCallback, Handler>
+ private HashMap<DynamicSensorCallback, Handler>
mDynamicSensorCallbacks = new HashMap<>();
private BroadcastReceiver mDynamicSensorBroadcastReceiver;
@@ -84,8 +89,8 @@
/** {@hide} */
public SystemSensorManager(Context context, Looper mainLooper) {
synchronized(sLock) {
- if (!sSensorModuleInitialized) {
- sSensorModuleInitialized = true;
+ if (!sNativeClassInited) {
+ sNativeClassInited = true;
nativeClassInit();
}
}
@@ -115,7 +120,7 @@
@Override
protected List<Sensor> getFullDynamicSensorList() {
// only set up broadcast receiver if the application tries to find dynamic sensors or
- // explicitly register a DynamicSensorConnectionCallback
+ // explicitly register a DynamicSensorCallback
setupDynamicSensorBroadcastReceiver();
updateDynamicSensorList();
return mFullDynamicSensorsList;
@@ -349,9 +354,9 @@
Handler mainHandler = new Handler(mContext.getMainLooper());
- for (Map.Entry<DynamicSensorConnectionCallback, Handler> entry :
+ for (Map.Entry<DynamicSensorCallback, Handler> entry :
mDynamicSensorCallbacks.entrySet()) {
- final DynamicSensorConnectionCallback callback = entry.getKey();
+ final DynamicSensorCallback callback = entry.getKey();
Handler handler =
entry.getValue() == null ? mainHandler : entry.getValue();
@@ -408,7 +413,7 @@
/** @hide */
protected void registerDynamicSensorCallbackImpl(
- DynamicSensorConnectionCallback callback, Handler handler) {
+ DynamicSensorCallback callback, Handler handler) {
if (DEBUG_DYNAMIC_SENSOR) {
Log.i(TAG, "DYNS Register dynamic sensor callback");
}
@@ -427,7 +432,7 @@
/** @hide */
protected void unregisterDynamicSensorCallbackImpl(
- DynamicSensorConnectionCallback callback) {
+ DynamicSensorCallback callback) {
if (DEBUG_DYNAMIC_SENSOR) {
Log.i(TAG, "Removing dynamic sensor listerner");
}
diff --git a/core/java/android/hardware/camera2/CameraMetadata.java b/core/java/android/hardware/camera2/CameraMetadata.java
index 4add962..d06e08b 100644
--- a/core/java/android/hardware/camera2/CameraMetadata.java
+++ b/core/java/android/hardware/camera2/CameraMetadata.java
@@ -2025,11 +2025,20 @@
* produced in response to a capture request submitted
* while in HDR mode.</p>
* <p>Since substantial post-processing is generally needed to
- * produce an HDR image, only YUV and JPEG outputs are
- * supported for LIMITED/FULL device HDR captures, and only
- * JPEG outputs are supported for LEGACY HDR
- * captures. Using a RAW output for HDR capture is not
+ * produce an HDR image, only YUV, PRIVATE, and JPEG
+ * outputs are supported for LIMITED/FULL device HDR
+ * captures, and only JPEG outputs are supported for LEGACY
+ * HDR captures. Using a RAW output for HDR capture is not
* supported.</p>
+ * <p>Some devices may also support always-on HDR, which
+ * applies HDR processing at full frame rate. For these
+ * devices, intents other than STILL_CAPTURE will also
+ * produce an HDR output with no frame rate impact compared
+ * to normal operation, though the quality may be lower
+ * than for STILL_CAPTURE intents.</p>
+ * <p>If SCENE_MODE_HDR is used with unsupported output types
+ * or capture intents, the images captured will be as if
+ * the SCENE_MODE was not enabled at all.</p>
*
* @see CaptureRequest#CONTROL_CAPTURE_INTENT
* @see CaptureRequest#CONTROL_SCENE_MODE
diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java
index 5748726..4f41e1c 100644
--- a/core/java/android/hardware/camera2/CaptureResult.java
+++ b/core/java/android/hardware/camera2/CaptureResult.java
@@ -3373,7 +3373,7 @@
/**
* <p>Maximum raw value output by sensor for this frame.</p>
- * <p>Since the android.sensor.blackLevel may change for different
+ * <p>Since the {@link CameraCharacteristics#SENSOR_BLACK_LEVEL_PATTERN android.sensor.blackLevelPattern} may change for different
* capture settings (e.g., {@link CaptureRequest#SENSOR_SENSITIVITY android.sensor.sensitivity}), the white
* level will change accordingly. This key is similar to
* {@link CameraCharacteristics#SENSOR_INFO_WHITE_LEVEL android.sensor.info.whiteLevel}, but specifies the camera device
@@ -3385,6 +3385,7 @@
* >= 0</p>
* <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
*
+ * @see CameraCharacteristics#SENSOR_BLACK_LEVEL_PATTERN
* @see CameraCharacteristics#SENSOR_INFO_WHITE_LEVEL
* @see CameraCharacteristics#SENSOR_OPTICAL_BLACK_REGIONS
* @see CaptureRequest#SENSOR_SENSITIVITY
diff --git a/core/java/android/hardware/camera2/legacy/CameraDeviceState.java b/core/java/android/hardware/camera2/legacy/CameraDeviceState.java
index 2c2ad1c..b0b94e3 100644
--- a/core/java/android/hardware/camera2/legacy/CameraDeviceState.java
+++ b/core/java/android/hardware/camera2/legacy/CameraDeviceState.java
@@ -70,7 +70,7 @@
* CameraDeviceStateListener callbacks to be called after state transitions.
*/
public interface CameraDeviceStateListener {
- void onError(int errorCode, RequestHolder holder);
+ void onError(int errorCode, Object errorArg, RequestHolder holder);
void onConfiguring();
void onIdle();
void onBusy();
@@ -162,11 +162,12 @@
* @param captureError Report a recoverable error for a single buffer or result using a valid
* error code for {@code ICameraDeviceCallbacks}, or
* {@link #NO_CAPTURE_ERROR}.
+ * @param captureErrorArg An argument for some error captureError codes.
* @return {@code false} if an error has occurred.
*/
public synchronized boolean setCaptureResult(final RequestHolder request,
- final CameraMetadataNative result,
- final int captureError) {
+ final CameraMetadataNative result,
+ final int captureError, final Object captureErrorArg) {
if (mCurrentState != STATE_CAPTURING) {
Log.e(TAG, "Cannot receive result while in state: " + mCurrentState);
mCurrentError = CameraDeviceImpl.CameraDeviceCallbacks.ERROR_CAMERA_DEVICE;
@@ -179,7 +180,7 @@
mCurrentHandler.post(new Runnable() {
@Override
public void run() {
- mCurrentListener.onError(captureError, request);
+ mCurrentListener.onError(captureError, captureErrorArg, request);
}
});
} else {
@@ -194,6 +195,11 @@
return mCurrentError == NO_CAPTURE_ERROR;
}
+ public synchronized boolean setCaptureResult(final RequestHolder request,
+ final CameraMetadataNative result) {
+ return setCaptureResult(request, result, NO_CAPTURE_ERROR, /*errorArg*/null);
+ }
+
/**
* Set the listener for state transition callbacks.
*
@@ -239,7 +245,7 @@
mCurrentHandler.post(new Runnable() {
@Override
public void run() {
- mCurrentListener.onError(mCurrentError, mCurrentRequest);
+ mCurrentListener.onError(mCurrentError, /*errorArg*/null, mCurrentRequest);
}
});
}
@@ -299,7 +305,7 @@
mCurrentHandler.post(new Runnable() {
@Override
public void run() {
- mCurrentListener.onError(error, mCurrentRequest);
+ mCurrentListener.onError(error, /*errorArg*/null, mCurrentRequest);
}
});
} else {
diff --git a/core/java/android/hardware/camera2/legacy/CameraDeviceUserShim.java b/core/java/android/hardware/camera2/legacy/CameraDeviceUserShim.java
index d01c275..f99928a 100644
--- a/core/java/android/hardware/camera2/legacy/CameraDeviceUserShim.java
+++ b/core/java/android/hardware/camera2/legacy/CameraDeviceUserShim.java
@@ -480,19 +480,15 @@
throw new ServiceSpecificException(ICameraService.ERROR_DISCONNECTED, err);
}
- ArrayList<Surface> surfaces = null;
+ SparseArray<Surface> surfaces = null;
synchronized(mConfigureLock) {
if (!mConfiguring) {
String err = "Cannot end configure, no configuration change in progress.";
Log.e(TAG, err);
throw new ServiceSpecificException(ICameraService.ERROR_INVALID_OPERATION, err);
}
- int numSurfaces = mSurfaces.size();
- if (numSurfaces > 0) {
- surfaces = new ArrayList<>();
- for (int i = 0; i < numSurfaces; ++i) {
- surfaces.add(mSurfaces.valueAt(i));
- }
+ if (mSurfaces != null) {
+ surfaces = mSurfaces.clone();
}
mConfiguring = false;
}
diff --git a/core/java/android/hardware/camera2/legacy/CaptureCollector.java b/core/java/android/hardware/camera2/legacy/CaptureCollector.java
index eb48a01..113927c 100644
--- a/core/java/android/hardware/camera2/legacy/CaptureCollector.java
+++ b/core/java/android/hardware/camera2/legacy/CaptureCollector.java
@@ -19,7 +19,7 @@
import android.util.Log;
import android.util.MutableLong;
import android.util.Pair;
-
+import android.view.Surface;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.TreeSet;
@@ -95,22 +95,28 @@
} else {
// Send buffer dropped errors for each pending buffer if the request has
// started.
- if (mFailedPreview) {
- Log.w(TAG, "Preview buffers dropped for request: " +
- mRequest.getRequestId());
- for (int i = 0; i < mRequest.numPreviewTargets(); i++) {
- CaptureCollector.this.mDeviceState.setCaptureResult(mRequest,
- /*result*/null,
- CameraDeviceImpl.CameraDeviceCallbacks.ERROR_CAMERA_BUFFER);
- }
- }
- if (mFailedJpeg) {
- Log.w(TAG, "Jpeg buffers dropped for request: " +
- mRequest.getRequestId());
- for (int i = 0; i < mRequest.numJpegTargets(); i++) {
- CaptureCollector.this.mDeviceState.setCaptureResult(mRequest,
- /*result*/null,
- CameraDeviceImpl.CameraDeviceCallbacks.ERROR_CAMERA_BUFFER);
+ for (Surface targetSurface : mRequest.getRequest().getTargets() ) {
+ try {
+ if (mRequest.jpegType(targetSurface)) {
+ if (mFailedJpeg) {
+ CaptureCollector.this.mDeviceState.setCaptureResult(mRequest,
+ /*result*/null,
+ CameraDeviceImpl.CameraDeviceCallbacks.
+ ERROR_CAMERA_BUFFER,
+ targetSurface);
+ }
+ } else {
+ // preview buffer
+ if (mFailedPreview) {
+ CaptureCollector.this.mDeviceState.setCaptureResult(mRequest,
+ /*result*/null,
+ CameraDeviceImpl.CameraDeviceCallbacks.
+ ERROR_CAMERA_BUFFER,
+ targetSurface);
+ }
+ }
+ } catch (LegacyExceptionUtils.BufferQueueAbandonedException e) {
+ Log.e(TAG, "Unexpected exception when querying Surface: " + e);
}
}
}
diff --git a/core/java/android/hardware/camera2/legacy/LegacyCameraDevice.java b/core/java/android/hardware/camera2/legacy/LegacyCameraDevice.java
index 661edd7..6c95869 100644
--- a/core/java/android/hardware/camera2/legacy/LegacyCameraDevice.java
+++ b/core/java/android/hardware/camera2/legacy/LegacyCameraDevice.java
@@ -36,6 +36,7 @@
import android.util.Log;
import android.util.Pair;
import android.util.Size;
+import android.util.SparseArray;
import android.view.Surface;
import java.util.ArrayList;
@@ -64,7 +65,7 @@
private final CameraCharacteristics mStaticCharacteristics;
private final ICameraDeviceCallbacks mDeviceCallbacks;
private final CameraDeviceState mDeviceState = new CameraDeviceState();
- private List<Surface> mConfiguredSurfaces;
+ private SparseArray<Surface> mConfiguredSurfaces;
private boolean mClosed = false;
private final ConditionVariable mIdle = new ConditionVariable(/*open*/true);
@@ -89,13 +90,29 @@
public static final int NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW = 1;
private CaptureResultExtras getExtrasFromRequest(RequestHolder holder) {
+ return getExtrasFromRequest(holder,
+ /*errorCode*/CameraDeviceState.NO_CAPTURE_ERROR, /*errorArg*/null);
+ }
+
+ private CaptureResultExtras getExtrasFromRequest(RequestHolder holder,
+ int errorCode, Object errorArg) {
+ int errorStreamId = -1;
+ if (errorCode == CameraDeviceImpl.CameraDeviceCallbacks.ERROR_CAMERA_BUFFER) {
+ Surface errorTarget = (Surface) errorArg;
+ int indexOfTarget = mConfiguredSurfaces.indexOfValue(errorTarget);
+ if (indexOfTarget < 0) {
+ Log.e(TAG, "Buffer drop error reported for unknown Surface");
+ } else {
+ errorStreamId = mConfiguredSurfaces.keyAt(indexOfTarget);
+ }
+ }
if (holder == null) {
return new CaptureResultExtras(ILLEGAL_VALUE, ILLEGAL_VALUE, ILLEGAL_VALUE,
ILLEGAL_VALUE, ILLEGAL_VALUE, ILLEGAL_VALUE, ILLEGAL_VALUE);
}
return new CaptureResultExtras(holder.getRequestId(), holder.getSubsequeceId(),
/*afTriggerId*/0, /*precaptureTriggerId*/0, holder.getFrameNumber(),
- /*partialResultCount*/1, /*errorStreamId*/-1);
+ /*partialResultCount*/1, errorStreamId);
}
/**
@@ -105,9 +122,9 @@
private final CameraDeviceState.CameraDeviceStateListener mStateListener =
new CameraDeviceState.CameraDeviceStateListener() {
@Override
- public void onError(final int errorCode, final RequestHolder holder) {
+ public void onError(final int errorCode, final Object errorArg, final RequestHolder holder) {
if (DEBUG) {
- Log.d(TAG, "onError called, errorCode = " + errorCode);
+ Log.d(TAG, "onError called, errorCode = " + errorCode + ", errorArg = " + errorArg);
}
switch (errorCode) {
/*
@@ -125,7 +142,7 @@
}
}
- final CaptureResultExtras extras = getExtrasFromRequest(holder);
+ final CaptureResultExtras extras = getExtrasFromRequest(holder, errorCode, errorArg);
mResultHandler.post(new Runnable() {
@Override
public void run() {
@@ -281,14 +298,17 @@
*
* <p>Every surface in {@code outputs} must be non-{@code null}.</p>
*
- * @param outputs a list of surfaces to set.
+ * @param outputs a list of surfaces to set. LegacyCameraDevice will take ownership of this
+ * list; it must not be modified by the caller once it's passed in.
* @return an error code for this binder operation, or {@link NO_ERROR}
* on success.
*/
- public int configureOutputs(List<Surface> outputs) {
+ public int configureOutputs(SparseArray<Surface> outputs) {
List<Pair<Surface, Size>> sizedSurfaces = new ArrayList<>();
if (outputs != null) {
- for (Surface output : outputs) {
+ int count = outputs.size();
+ for (int i = 0; i < count; i++) {
+ Surface output = outputs.valueAt(i);
if (output == null) {
Log.e(TAG, "configureOutputs - null outputs are not allowed");
return BAD_VALUE;
@@ -353,7 +373,7 @@
}
if (success) {
- mConfiguredSurfaces = outputs != null ? new ArrayList<>(outputs) : null;
+ mConfiguredSurfaces = outputs;
} else {
return LegacyExceptionUtils.INVALID_OPERATION;
}
@@ -659,6 +679,23 @@
return nativeGetSurfaceId(surface);
}
+ static List<Long> getSurfaceIds(SparseArray<Surface> surfaces) {
+ if (surfaces == null) {
+ throw new NullPointerException("Null argument surfaces");
+ }
+ List<Long> surfaceIds = new ArrayList<>();
+ int count = surfaces.size();
+ for (int i = 0; i < count; i++) {
+ long id = getSurfaceId(surfaces.valueAt(i));
+ if (id == 0) {
+ throw new IllegalStateException(
+ "Configured surface had null native GraphicBufferProducer pointer!");
+ }
+ surfaceIds.add(id);
+ }
+ return surfaceIds;
+ }
+
static List<Long> getSurfaceIds(Collection<Surface> surfaces) {
if (surfaces == null) {
throw new NullPointerException("Null argument surfaces");
diff --git a/core/java/android/hardware/camera2/legacy/RequestHolder.java b/core/java/android/hardware/camera2/legacy/RequestHolder.java
index 9b628fb..476c3de 100644
--- a/core/java/android/hardware/camera2/legacy/RequestHolder.java
+++ b/core/java/android/hardware/camera2/legacy/RequestHolder.java
@@ -41,6 +41,8 @@
private final int mNumPreviewTargets;
private volatile boolean mFailed = false;
+ private final Collection<Long> mJpegSurfaceIds;
+
/**
* A builder class for {@link RequestHolder} objects.
*
@@ -150,13 +152,13 @@
*/
public RequestHolder build(long frameNumber) {
return new RequestHolder(mRequestId, mSubsequenceId, mRequest, mRepeating, frameNumber,
- mNumJpegTargets, mNumPreviewTargets);
+ mNumJpegTargets, mNumPreviewTargets, mJpegSurfaceIds);
}
}
private RequestHolder(int requestId, int subsequenceId, CaptureRequest request,
boolean repeating, long frameNumber, int numJpegTargets,
- int numPreviewTargets) {
+ int numPreviewTargets, Collection<Long> jpegSurfaceIds) {
mRepeating = repeating;
mRequest = request;
mRequestId = requestId;
@@ -164,6 +166,7 @@
mFrameNumber = frameNumber;
mNumJpegTargets = numJpegTargets;
mNumPreviewTargets = numPreviewTargets;
+ mJpegSurfaceIds = jpegSurfaceIds;
}
/**
@@ -238,6 +241,17 @@
}
/**
+ * Returns true if the given surface requires jpeg buffers.
+ *
+ * @param s a {@link android.view.Surface} to check.
+ * @return true if the surface requires a jpeg buffer.
+ */
+ public boolean jpegType(Surface s)
+ throws LegacyExceptionUtils.BufferQueueAbandonedException {
+ return LegacyCameraDevice.containsSurfaceId(s, mJpegSurfaceIds);
+ }
+
+ /**
* Mark this request as failed.
*/
public void failRequest() {
diff --git a/core/java/android/hardware/camera2/legacy/RequestThreadManager.java b/core/java/android/hardware/camera2/legacy/RequestThreadManager.java
index e8ce3ec..a3fdd56 100644
--- a/core/java/android/hardware/camera2/legacy/RequestThreadManager.java
+++ b/core/java/android/hardware/camera2/legacy/RequestThreadManager.java
@@ -908,8 +908,7 @@
mFaceDetectMapper.mapResultFaces(result, mLastRequest);
if (!holder.requestFailed()) {
- mDeviceState.setCaptureResult(holder, result,
- CameraDeviceState.NO_CAPTURE_ERROR);
+ mDeviceState.setCaptureResult(holder, result);
}
}
if (DEBUG) {
diff --git a/core/java/android/hardware/location/ContextHubInfo.java b/core/java/android/hardware/location/ContextHubInfo.java
index 644e29f..ae44f1d 100644
--- a/core/java/android/hardware/location/ContextHubInfo.java
+++ b/core/java/android/hardware/location/ContextHubInfo.java
@@ -37,6 +37,7 @@
private float mStoppedPowerDrawMw;
private float mSleepPowerDrawMw;
private float mPeakPowerDrawMw;
+ private int mMaxPacketLengthBytes;
private int[] mSupportedSensors;
@@ -46,6 +47,27 @@
}
/**
+ * returns the maximum number of bytes that can be sent per message to the hub
+ *
+ * @return int - maximum bytes that can be transmitted in a
+ * single packet
+ */
+ public int getMaxPacketLengthBytes() {
+ return mMaxPacketLengthBytes;
+ }
+
+ /**
+ * set the context hub unique identifer
+ *
+ * @param bytes - Maximum number of bytes per message
+ *
+ * @hide
+ */
+ public void setMaxPacketLenBytes(int bytes) {
+ mMaxPacketLengthBytes = bytes;
+ }
+
+ /**
* get the context hub unique identifer
*
* @return int - unique system wide identifier
@@ -374,4 +396,4 @@
return new ContextHubInfo[size];
}
};
-}
+}
\ No newline at end of file
diff --git a/core/java/android/hardware/location/ContextHubManager.java b/core/java/android/hardware/location/ContextHubManager.java
index 4ddf767..89edaa9 100644
--- a/core/java/android/hardware/location/ContextHubManager.java
+++ b/core/java/android/hardware/location/ContextHubManager.java
@@ -43,23 +43,6 @@
private Handler mCallbackHandler;
/**
- * A special context hub identifier meaning any possible hub on the system.
- */
- public static final int ANY_HUB = -1;
- /**
- * A constant denoting a message to load a a Nano App
- */
- public static final int MSG_LOAD_NANO_APP = 1;
- /**
- * A constant denoting a message to unload a a Nano App
- */
- public static final int MSG_UNLOAD_NANO_APP = 2;
- /**
- * A constant denoting a message to send a message
- */
- public static final int MSG_DATA_SEND = 3;
-
- /**
* An interface to receive asynchronous communication from the context hub.
*/
public abstract static class Callback {
@@ -69,7 +52,7 @@
* Callback function called on message receipt from context hub.
*
* @param hubHandle Handle (system-wide unique identifier) of the hub of the message.
- * @param nanoAppHandle Handle (unique identifier) for the app that sent the message.
+ * @param nanoAppHandle Handle (unique identifier) for app instance that sent the message.
* @param message The context hub message.
*
* @see ContextHubMessage
@@ -89,7 +72,7 @@
try {
retVal = getBinder().getContextHubHandles();
} catch (RemoteException e) {
- Log.e(TAG, "Could not fetch context hub handles : " + e);
+ Log.w(TAG, "Could not fetch context hub handles : " + e);
}
return retVal;
}
@@ -107,7 +90,7 @@
try {
retVal = getBinder().getContextHubInfo(hubHandle);
} catch (RemoteException e) {
- Log.e(TAG, "Could not fetch context hub info :" + e);
+ Log.w(TAG, "Could not fetch context hub info :" + e);
}
return retVal;
@@ -126,6 +109,7 @@
*/
public int loadNanoApp(int hubHandle, NanoApp app) {
int retVal = -1;
+
if (app == null) {
return retVal;
}
@@ -133,7 +117,7 @@
try {
retVal = getBinder().loadNanoApp(hubHandle, app);
} catch (RemoteException e) {
- Log.e(TAG, "Could not fetch load nanoApp :" + e);
+ Log.w(TAG, "Could not load nanoApp :" + e);
}
return retVal;
@@ -152,7 +136,7 @@
try {
retVal = getBinder().unloadNanoApp(nanoAppHandle);
} catch (RemoteException e) {
- Log.e(TAG, "Could not fetch unload nanoApp :" + e);
+ Log.w(TAG, "Could not fetch unload nanoApp :" + e);
}
return retVal;
@@ -172,7 +156,7 @@
try {
retVal = getBinder().getNanoAppInstanceInfo(nanoAppHandle);
} catch (RemoteException e) {
- Log.e(TAG, "Could not fetch nanoApp info :" + e);
+ Log.w(TAG, "Could not fetch nanoApp info :" + e);
}
return retVal;
@@ -193,7 +177,7 @@
try {
retVal = getBinder().findNanoAppOnHub(hubHandle, filter);
} catch (RemoteException e) {
- Log.e(TAG, "Could not query nanoApp instance :" + e);
+ Log.w(TAG, "Could not query nanoApp instance :" + e);
}
return retVal;
}
@@ -212,10 +196,14 @@
public int sendMessage(int hubHandle, int nanoAppHandle, ContextHubMessage message) {
int retVal = -1;
+ if (message == null || message.getData() == null) {
+ Log.w(TAG, "null ptr");
+ return retVal;
+ }
try {
retVal = getBinder().sendMessage(hubHandle, nanoAppHandle, message);
} catch (RemoteException e) {
- Log.e(TAG, "Could not fetch send message :" + e.toString());
+ Log.w(TAG, "Could not send message :" + e.toString());
}
return retVal;
@@ -247,7 +235,7 @@
public int registerCallback(Callback callback, Handler handler) {
synchronized(this) {
if (mCallback != null) {
- Log.e(TAG, "Max number of callbacks reached!");
+ Log.w(TAG, "Max number of callbacks reached!");
return -1;
}
mCallback = callback;
@@ -268,7 +256,7 @@
public int unregisterCallback(Callback callback) {
synchronized(this) {
if (callback != mCallback) {
- Log.e(TAG, "Cannot recognize callback!");
+ Log.w(TAG, "Cannot recognize callback!");
return -1;
}
@@ -311,11 +299,11 @@
try {
getBinder().registerCallback(mClientCallback);
} catch (RemoteException e) {
- Log.e(TAG, "Could not register callback:" + e);
+ Log.w(TAG, "Could not register callback:" + e);
}
} else {
- Log.d(TAG, "failed to getService");
+ Log.w(TAG, "failed to getService");
}
}
diff --git a/core/java/android/hardware/location/ContextHubMessage.java b/core/java/android/hardware/location/ContextHubMessage.java
index 954e97d..bca2ae6 100644
--- a/core/java/android/hardware/location/ContextHubMessage.java
+++ b/core/java/android/hardware/location/ContextHubMessage.java
@@ -16,10 +16,10 @@
package android.hardware.location;
-
import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;
+import android.util.Log;
import java.util.Arrays;
@@ -32,6 +32,9 @@
private int mVersion;
private byte[]mData;
+ private static final String TAG = "ContextHubMessage";
+
+
/**
* Get the message type
*
@@ -106,9 +109,11 @@
private ContextHubMessage(Parcel in) {
mType = in.readInt();
mVersion = in.readInt();
- byte[] byteBuffer = new byte[in.readInt()];
- in.readByteArray(byteBuffer);
+ int bufferLength = in.readInt();
+ mData = new byte[bufferLength];
+ in.readByteArray(mData);
}
+
public void writeToParcel(Parcel out, int flags) {
out.writeInt(mType);
out.writeInt(mVersion);
diff --git a/core/java/android/hardware/location/ContextHubService.java b/core/java/android/hardware/location/ContextHubService.java
index 274babe..3e6cb63 100644
--- a/core/java/android/hardware/location/ContextHubService.java
+++ b/core/java/android/hardware/location/ContextHubService.java
@@ -29,12 +29,30 @@
*/
public class ContextHubService extends IContextHubService.Stub {
+ public static final String CONTEXTHUB_SERVICE = "contexthub_service";
+
private static final String TAG = "ContextHubService";
private static final String HARDWARE_PERMISSION = Manifest.permission.LOCATION_HARDWARE;
private static final String ENFORCE_HW_PERMISSION_MESSAGE = "Permission '"
+ HARDWARE_PERMISSION + "' not granted to access ContextHub Hardware";
- public static final String CONTEXTHUB_SERVICE = "contexthub_service";
+
+ public static final int ANY_HUB = -1;
+ public static final int MSG_LOAD_NANO_APP = 3;
+ public static final int MSG_UNLOAD_NANO_APP = 4;
+
+ private static final String PRE_LOADED_GENERIC_UNKNOWN = "Preloaded app, unknown";
+ private static final String PRE_LOADED_APP_NAME = PRE_LOADED_GENERIC_UNKNOWN;
+ private static final String PRE_LOADED_APP_PUBLISHER = PRE_LOADED_GENERIC_UNKNOWN;
+ private static final int PRE_LOADED_APP_MEM_REQ = 0;
+
+ private static final int MSG_HEADER_SIZE = 4;
+ private static final int MSG_FIELD_TYPE = 0;
+ private static final int MSG_FIELD_VERSION = 1;
+ private static final int MSG_FIELD_HUB_HANDLE = 2;
+ private static final int MSG_FIELD_APP_INSTANCE = 3;
+
+ private static final int OS_APP_INSTANCE = -1;
private final Context mContext;
@@ -42,44 +60,27 @@
private ContextHubInfo[] mContextHubInfo;
private IContextHubCallback mCallback;
+ private native int nativeSendMessage(int[] header, byte[] data);
+ private native ContextHubInfo[] nativeInitialize();
+
+
public ContextHubService(Context context) {
mContext = context;
mContextHubInfo = nativeInitialize();
+ mNanoAppHash = new HashMap<Integer, NanoAppInstanceInfo>();
for (int i = 0; i < mContextHubInfo.length; i++) {
- Log.v(TAG, "ContextHub[" + i + "] id: " + mContextHubInfo[i].getId()
+ Log.d(TAG, "ContextHub[" + i + "] id: " + mContextHubInfo[i].getId()
+ ", name: " + mContextHubInfo[i].getName());
}
}
- private native int nativeSendMessage(int[] header, byte[] data);
- private native ContextHubInfo[] nativeInitialize();
-
@Override
- public int registerCallback(IContextHubCallback callback) throws RemoteException{
+ public int registerCallback(IContextHubCallback callback) throws RemoteException {
checkPermissions();
- mCallback = callback;
- return 0;
- }
-
-
- private int onMessageReceipt(int[] header, byte[] data) {
- if (mCallback != null) {
- // TODO : Defend against unexpected header sizes
- // Add abstraction for magic numbers
- // onMessageRecipt should pass the right arguments
- ContextHubMessage msg = new ContextHubMessage(header[0], header[1], data);
-
- try {
- mCallback.onMessageReceipt(0, 0, msg);
- } catch (Exception e) {
- Log.e(TAG, "Exception " + e + " when calling remote callback");
- return -1;
- }
- } else {
- Log.d(TAG, "Message Callback is NULL");
+ synchronized(this) {
+ mCallback = callback;
}
-
return 0;
}
@@ -118,14 +119,17 @@
}
// Call Native interface here
- int[] msgHeader = new int[8];
- msgHeader[0] = contextHubHandle;
- msgHeader[1] = app.getAppId();
- msgHeader[2] = app.getAppVersion();
- msgHeader[3] = ContextHubManager.MSG_LOAD_NANO_APP;
- msgHeader[4] = 0; // Loading hints
+ int[] msgHeader = new int[MSG_HEADER_SIZE];
+ msgHeader[MSG_FIELD_HUB_HANDLE] = contextHubHandle;
+ msgHeader[MSG_FIELD_APP_INSTANCE] = OS_APP_INSTANCE;
+ msgHeader[MSG_FIELD_VERSION] = 0;
+ msgHeader[MSG_FIELD_TYPE] = MSG_LOAD_NANO_APP;
- return nativeSendMessage(msgHeader, app.getAppBinary());
+ if (nativeSendMessage(msgHeader, app.getAppBinary()) != 0) {
+ return -1;
+ }
+ // Do not add an entry to mNanoAppInstance Hash yet. The HAL may reject the app
+ return 0;
}
@Override
@@ -137,12 +141,18 @@
}
// Call Native interface here
- int[] msgHeader = new int[8];
- msgHeader[0] = info.getContexthubId();
- msgHeader[1] = ContextHubManager.MSG_UNLOAD_NANO_APP;
- msgHeader[2] = info.getHandle();
+ int[] msgHeader = new int[MSG_HEADER_SIZE];
+ msgHeader[MSG_FIELD_HUB_HANDLE] = ANY_HUB;
+ msgHeader[MSG_FIELD_APP_INSTANCE] = OS_APP_INSTANCE;
+ msgHeader[MSG_FIELD_VERSION] = 0;
+ msgHeader[MSG_FIELD_TYPE] = MSG_UNLOAD_NANO_APP;
- return nativeSendMessage(msgHeader, null);
+ if(nativeSendMessage(msgHeader, null) != 0) {
+ return -1;
+ }
+
+ // Do not add an entry to mNanoAppInstance Hash yet. The HAL may reject the app
+ return 0;
}
@Override
@@ -166,7 +176,7 @@
for(Integer nanoAppInstance : mNanoAppHash.keySet()) {
NanoAppInstanceInfo info = mNanoAppHash.get(nanoAppInstance);
- if(filter.testMatch(info)){
+ if (filter.testMatch(info)){
foundInstances.add(nanoAppInstance);
}
}
@@ -183,12 +193,12 @@
public int sendMessage(int hubHandle, int nanoAppHandle, ContextHubMessage msg)
throws RemoteException {
checkPermissions();
- int[] msgHeader = new int[8];
- msgHeader[0] = ContextHubManager.MSG_DATA_SEND;
- msgHeader[1] = hubHandle;
- msgHeader[2] = nanoAppHandle;
- msgHeader[3] = msg.getMsgType();
- msgHeader[4] = msg.getVersion();
+
+ int[] msgHeader = new int[MSG_HEADER_SIZE];
+ msgHeader[MSG_FIELD_HUB_HANDLE] = hubHandle;
+ msgHeader[MSG_FIELD_APP_INSTANCE] = nanoAppHandle;
+ msgHeader[MSG_FIELD_VERSION] = msg.getVersion();
+ msgHeader[MSG_FIELD_TYPE] = msg.getMsgType();
return nativeSendMessage(msgHeader, msg.getData());
}
@@ -196,5 +206,52 @@
private void checkPermissions() {
mContext.enforceCallingPermission(HARDWARE_PERMISSION, ENFORCE_HW_PERMISSION_MESSAGE);
}
-}
+ private int onMessageReceipt(int[] header, byte[] data) {
+ if (header == null || data == null || header.length < MSG_HEADER_SIZE) {
+ return -1;
+ }
+
+ synchronized(this) {
+ if (mCallback != null) {
+ ContextHubMessage msg = new ContextHubMessage(header[MSG_FIELD_TYPE],
+ header[MSG_FIELD_VERSION],
+ data);
+
+ try {
+ mCallback.onMessageReceipt(header[MSG_FIELD_HUB_HANDLE],
+ header[MSG_FIELD_APP_INSTANCE],
+ msg);
+ } catch (Exception e) {
+ Log.w(TAG, "Exception " + e + " when calling remote callback");
+ return -1;
+ }
+ } else {
+ Log.d(TAG, "Message Callback is NULL");
+ }
+ }
+
+ return 0;
+ }
+
+ private int addAppInstance(int hubHandle, int appInstanceHandle, long appId, int appVersion) {
+ // App Id encodes vendor & version
+ NanoAppInstanceInfo appInfo = new NanoAppInstanceInfo();
+
+ appInfo.setAppId(appId);
+ appInfo.setAppVersion(appVersion);
+ appInfo.setName(PRE_LOADED_APP_NAME);
+ appInfo.setContexthubId(hubHandle);
+ appInfo.setHandle(appInstanceHandle);
+ appInfo.setPublisher(PRE_LOADED_APP_PUBLISHER);
+ appInfo.setNeededExecMemBytes(PRE_LOADED_APP_MEM_REQ);
+ appInfo.setNeededReadMemBytes(PRE_LOADED_APP_MEM_REQ);
+ appInfo.setNeededWriteMemBytes(PRE_LOADED_APP_MEM_REQ);
+
+ mNanoAppHash.put(appInstanceHandle, appInfo);
+ Log.d(TAG, "Added app instance " + appInstanceHandle + " with id " + appId
+ + " version " + appVersion);
+
+ return 0;
+ }
+}
diff --git a/core/java/android/hardware/location/NanoAppFilter.java b/core/java/android/hardware/location/NanoAppFilter.java
index 369f9e4..8db70e9 100644
--- a/core/java/android/hardware/location/NanoAppFilter.java
+++ b/core/java/android/hardware/location/NanoAppFilter.java
@@ -20,6 +20,7 @@
import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;
+import android.util.Log;
/**
* @hide
@@ -27,6 +28,8 @@
@SystemApi
public class NanoAppFilter {
+ private static final String TAG = "NanoAppFilter";
+
// The appId, can be set to APP_ID_ANY
private long mAppId;
@@ -54,6 +57,10 @@
* If this flag is set, only versions strictly less than the version specified shall match.
*/
public static final int FLAGS_VERSION_LESS_THAN = 4;
+ /**
+ * If this flag is set, only versions strictly equal to the
+ * version specified shall match.
+ */
public static final int FLAGS_VERSION_STRICTLY_EQUAL = 8;
/**
@@ -117,14 +124,9 @@
* @return true if this is a match, false otherwise
*/
public boolean testMatch(NanoAppInstanceInfo info) {
- if ((mContextHubId == HUB_ANY || info.getContexthubId() == mContextHubId) &&
+ return (mContextHubId == HUB_ANY || info.getContexthubId() == mContextHubId) &&
(mAppId == APP_ANY || info.getAppId() == mAppId) &&
- // (mAppIdVendorMask == VENDOR_ANY) TODO : Expose Vendor mask cleanly
- (versionsMatch(mVersionRestrictionMask, mAppVersion, info.getAppVersion()))) {
- return true;
- } else {
- return false;
- }
+ (versionsMatch(mVersionRestrictionMask, mAppVersion, info.getAppVersion()));
}
public static final Parcelable.Creator<NanoAppFilter> CREATOR
diff --git a/core/java/android/hardware/location/NanoAppInstanceInfo.java b/core/java/android/hardware/location/NanoAppInstanceInfo.java
index ac62919..977f645 100644
--- a/core/java/android/hardware/location/NanoAppInstanceInfo.java
+++ b/core/java/android/hardware/location/NanoAppInstanceInfo.java
@@ -29,7 +29,7 @@
private String mPublisher;
private String mName;
- private int mAppId;
+ private long mAppId;
private int mAppVersion;
private int mNeededReadMemBytes;
@@ -59,6 +59,8 @@
* set the publisher name for the app
*
* @param publisher - name of the publisher
+ *
+ * @hide
*/
public void setPublisher(String publisher) {
mPublisher = publisher;
@@ -77,6 +79,8 @@
* set the name of the app
*
* @param name - name of the app
+ *
+ * @hide
*/
public void setName(String name) {
mName = name;
@@ -87,7 +91,7 @@
*
* @return int - application identifier
*/
- public int getAppId() {
+ public long getAppId() {
return mAppId;
}
@@ -95,8 +99,10 @@
* Set the application identifier
*
* @param appId - application identifier
+ *
+ * @hide
*/
- public void setAppId(int appId) {
+ public void setAppId(long appId) {
mAppId = appId;
}
@@ -113,6 +119,8 @@
* Set the application version
*
* @param appVersion - version of the app
+ *
+ * @hide
*/
public void setAppVersion(int appVersion) {
mAppVersion = appVersion;
@@ -131,6 +139,8 @@
* Set the read memory needed by the app
*
* @param neededReadMemBytes - readable Memory needed in bytes
+ *
+ * @hide
*/
public void setNeededReadMemBytes(int neededReadMemBytes) {
mNeededReadMemBytes = neededReadMemBytes;
@@ -150,6 +160,8 @@
*
* @param neededWriteMemBytes - writable memory needed by the
* app
+ *
+ * @hide
*/
public void setNeededWriteMemBytes(int neededWriteMemBytes) {
mNeededWriteMemBytes = neededWriteMemBytes;
@@ -169,6 +181,8 @@
*
* @param neededExecMemBytes - executable memory needed by the
* app
+ *
+ * @hide
*/
public void setNeededExecMemBytes(int neededExecMemBytes) {
mNeededExecMemBytes = neededExecMemBytes;
@@ -187,6 +201,8 @@
* set the sensors needed by this app
*
* @param neededSensors - all the sensors needed by this app
+ *
+ * @hide
*/
public void setNeededSensors(int[] neededSensors) {
mNeededSensors = neededSensors;
@@ -206,6 +222,8 @@
*
* @param outputEvents - the events that may be generated by
* this app
+ *
+ * @hide
*/
public void setOutputEvents(int[] outputEvents) {
mOutputEvents = outputEvents;
@@ -224,6 +242,8 @@
* set the context hub identifier
*
* @param contexthubId - system wide unique identifier
+ *
+ * @hide
*/
public void setContexthubId(int contexthubId) {
mContexthubId = contexthubId;
@@ -242,6 +262,8 @@
* set the handle for an app instance
*
* @param handle - handle to this instance
+ *
+ * @hide
*/
public void setHandle(int handle) {
mHandle = handle;
@@ -252,7 +274,7 @@
mPublisher = in.readString();
mName = in.readString();
- mAppId = in.readInt();
+ mAppId = in.readLong();
mAppVersion = in.readInt();
mNeededReadMemBytes = in.readInt();
mNeededWriteMemBytes = in.readInt();
@@ -274,7 +296,7 @@
public void writeToParcel(Parcel out, int flags) {
out.writeString(mPublisher);
out.writeString(mName);
- out.writeInt(mAppId);
+ out.writeLong(mAppId);
out.writeInt(mAppVersion);
out.writeInt(mContexthubId);
out.writeInt(mNeededReadMemBytes);
@@ -286,7 +308,6 @@
out.writeInt(mOutputEvents.length);
out.writeIntArray(mOutputEvents);
-
}
public static final Parcelable.Creator<NanoAppInstanceInfo> CREATOR
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index 6b79a8a..9d53a00 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -295,9 +295,7 @@
boolean mLastShowInputRequested;
int mCandidatesVisibility;
CompletionInfo[] mCurCompletions;
-
- boolean mShowInputForced;
-
+
boolean mFullscreenApplied;
boolean mIsFullscreen;
View mExtractView;
@@ -422,7 +420,6 @@
boolean wasVis = isInputViewShown();
mShowInputFlags = 0;
mShowInputRequested = false;
- mShowInputForced = false;
doHideWindow();
clearInsetOfPreviousIme();
if (resultReceiver != null) {
@@ -439,8 +436,7 @@
public void showSoftInput(int flags, ResultReceiver resultReceiver) {
if (DEBUG) Log.v(TAG, "showSoftInput()");
boolean wasVis = isInputViewShown();
- mShowInputFlags = 0;
- if (onShowInputRequested(flags, false)) {
+ if (dispatchOnShowInputRequested(flags, false)) {
try {
showWindow(true);
} catch (BadTokenException e) {
@@ -817,8 +813,8 @@
mInitialized = false;
mWindowCreated = false;
mShowInputRequested = false;
- mShowInputForced = false;
-
+ mShowInputFlags = 0;
+
mThemeAttrs = obtainStyledAttributes(android.R.styleable.InputMethodService);
mRootView = mInflater.inflate(
com.android.internal.R.layout.input_method, null);
@@ -888,7 +884,7 @@
*/
@Override public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
-
+
boolean visible = mWindowVisible;
int showFlags = mShowInputFlags;
boolean showingInput = mShowInputRequested;
@@ -903,7 +899,7 @@
if (visible) {
if (showingInput) {
// If we were last showing the soft keyboard, try to do so again.
- if (onShowInputRequested(showFlags, true)) {
+ if (dispatchOnShowInputRequested(showFlags, true)) {
showWindow(true);
if (completions != null) {
mCurCompletions = completions;
@@ -1540,20 +1536,41 @@
return false;
}
}
- if ((flags&InputMethod.SHOW_FORCED) != 0) {
- mShowInputForced = true;
- }
return true;
}
-
+
+ /**
+ * A utility method to call {{@link #onShowInputRequested(int, boolean)}} and update internal
+ * states depending on its result. Since {@link #onShowInputRequested(int, boolean)} is
+ * exposed to IME authors as an overridable public method without {@code @CallSuper}, we have
+ * to have this method to ensure that those internal states are always updated no matter how
+ * {@link #onShowInputRequested(int, boolean)} is overridden by the IME author.
+ * @param flags Provides additional information about the show request,
+ * as per {@link InputMethod#showSoftInput InputMethod.showSoftInput()}.
+ * @param configChange This is true if we are re-showing due to a
+ * configuration change.
+ * @return Returns true to indicate that the window should be shown.
+ * @see #onShowInputRequested(int, boolean)
+ */
+ private boolean dispatchOnShowInputRequested(int flags, boolean configChange) {
+ final boolean result = onShowInputRequested(flags, configChange);
+ if (result) {
+ mShowInputFlags = flags;
+ } else {
+ mShowInputFlags = 0;
+ }
+ return result;
+ }
+
public void showWindow(boolean showInput) {
if (DEBUG) Log.v(TAG, "Showing window: showInput=" + showInput
+ " mShowInputRequested=" + mShowInputRequested
+ " mWindowAdded=" + mWindowAdded
+ " mWindowCreated=" + mWindowCreated
+ " mWindowVisible=" + mWindowVisible
- + " mInputStarted=" + mInputStarted);
-
+ + " mInputStarted=" + mInputStarted
+ + " mShowInputFlags=" + mShowInputFlags);
+
if (mInShowWindow) {
Log.w(TAG, "Re-entrance in to showWindow");
return;
@@ -2573,7 +2590,6 @@
p.println(" mShowInputRequested=" + mShowInputRequested
+ " mLastShowInputRequested=" + mLastShowInputRequested
- + " mShowInputForced=" + mShowInputForced
+ " mShowInputFlags=0x" + Integer.toHexString(mShowInputFlags));
p.println(" mCandidatesVisibility=" + mCandidatesVisibility
+ " mFullscreenApplied=" + mFullscreenApplied
diff --git a/core/java/android/net/ConnectivityMetricsEvent.aidl b/core/java/android/net/ConnectivityMetricsEvent.aidl
index da17561..a027d7c 100644
--- a/core/java/android/net/ConnectivityMetricsEvent.aidl
+++ b/core/java/android/net/ConnectivityMetricsEvent.aidl
@@ -17,3 +17,4 @@
package android.net;
parcelable ConnectivityMetricsEvent;
+parcelable ConnectivityMetricsEvent.Reference;
diff --git a/core/java/android/net/ConnectivityMetricsEvent.java b/core/java/android/net/ConnectivityMetricsEvent.java
index 098f1e6..b5d67d3 100644
--- a/core/java/android/net/ConnectivityMetricsEvent.java
+++ b/core/java/android/net/ConnectivityMetricsEvent.java
@@ -78,4 +78,42 @@
return String.format("ConnectivityMetricsEvent(%d, %d, %d)", timestamp,
componentTag, eventTag);
}
+
+ /** {@hide} */
+ public static class Reference implements Parcelable {
+
+ public long value;
+
+ public Reference(long ref) {
+ this.value = ref;
+ }
+
+ /** Implement the Parcelable interface */
+ public static final Parcelable.Creator<Reference> CREATOR
+ = new Parcelable.Creator<Reference> (){
+ public Reference createFromParcel(Parcel source) {
+ return new Reference(source.readLong());
+ }
+
+ public Reference[] newArray(int size) {
+ return new Reference[size];
+ }
+ };
+
+ /** Implement the Parcelable interface */
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ /** Implement the Parcelable interface */
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeLong(value);
+ }
+
+ public void readFromParcel(Parcel in) {
+ value = in.readLong();
+ }
+ }
}
diff --git a/core/java/android/net/ConnectivityMetricsLogger.java b/core/java/android/net/ConnectivityMetricsLogger.java
index 3ef8050..eafb8ac 100644
--- a/core/java/android/net/ConnectivityMetricsLogger.java
+++ b/core/java/android/net/ConnectivityMetricsLogger.java
@@ -15,6 +15,7 @@
*/
package android.net;
+import android.os.Bundle;
import android.os.Parcelable;
import android.os.RemoteException;
import android.os.ServiceManager;
@@ -28,14 +29,24 @@
public static final String CONNECTIVITY_METRICS_LOGGER_SERVICE = "connectivity_metrics_logger";
// Component Tags
- public static final int COMPONENT_TAG_CONNECTIVITY = 1;
- public static final int COMPONENT_TAG_BLUETOOTH = 2;
- public static final int COMPONENT_TAG_WIFI = 3;
- public static final int COMPONENT_TAG_TELECOM = 4;
- public static final int COMPONENT_TAG_TELEPHONY = 5;
+ public static final int COMPONENT_TAG_CONNECTIVITY = 0;
+ public static final int COMPONENT_TAG_BLUETOOTH = 1;
+ public static final int COMPONENT_TAG_WIFI = 2;
+ public static final int COMPONENT_TAG_TELECOM = 3;
+ public static final int COMPONENT_TAG_TELEPHONY = 4;
+
+ public static final int NUMBER_OF_COMPONENTS = 5;
+
+ // Event Tag
+ public static final int TAG_SKIPPED_EVENTS = -1;
+
+ public static final String DATA_KEY_EVENTS_COUNT = "count";
private IConnectivityMetricsLogger mService;
+ private long mServiceUnblockedTimestampMillis = 0;
+ private int mNumSkippedEvents = 0;
+
public ConnectivityMetricsLogger() {
mService = IConnectivityMetricsLogger.Stub.asInterface(ServiceManager.getService(
CONNECTIVITY_METRICS_LOGGER_SERVICE));
@@ -46,12 +57,51 @@
if (DBG) {
Log.d(TAG, "logEvent(" + componentTag + "," + eventTag + ") Service not ready");
}
- } else {
- try {
- mService.logEvent(new ConnectivityMetricsEvent(timestamp, componentTag, eventTag, data));
- } catch (RemoteException e) {
- Log.e(TAG, "Error logging event " + e.getMessage());
+ return;
+ }
+
+ if (mServiceUnblockedTimestampMillis > 0) {
+ if (System.currentTimeMillis() < mServiceUnblockedTimestampMillis) {
+ // Service is throttling events.
+ // Don't send new events because they will be dropped.
+ mNumSkippedEvents++;
+ return;
}
}
+
+ ConnectivityMetricsEvent skippedEventsEvent = null;
+ if (mNumSkippedEvents > 0) {
+ // Log number of skipped events
+ Bundle b = new Bundle();
+ b.putInt(DATA_KEY_EVENTS_COUNT, mNumSkippedEvents);
+ skippedEventsEvent = new ConnectivityMetricsEvent(mServiceUnblockedTimestampMillis,
+ componentTag, TAG_SKIPPED_EVENTS, b);
+
+ mServiceUnblockedTimestampMillis = 0;
+ }
+
+ ConnectivityMetricsEvent event = new ConnectivityMetricsEvent(timestamp, componentTag,
+ eventTag, data);
+
+ try {
+ long result;
+ if (skippedEventsEvent == null) {
+ result = mService.logEvent(event);
+ } else {
+ result = mService.logEvents(new ConnectivityMetricsEvent[]
+ {skippedEventsEvent, event});
+ }
+
+ if (result == 0) {
+ mNumSkippedEvents = 0;
+ } else {
+ mNumSkippedEvents++;
+ if (result > 0) { // events are throttled
+ mServiceUnblockedTimestampMillis = result;
+ }
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error logging event " + e.getMessage());
+ }
}
}
diff --git a/core/java/android/net/DhcpResults.java b/core/java/android/net/DhcpResults.java
index 97bd5d2..8c5f603 100644
--- a/core/java/android/net/DhcpResults.java
+++ b/core/java/android/net/DhcpResults.java
@@ -40,6 +40,9 @@
public int leaseDuration;
+ /** Link MTU option. 0 means unset. */
+ public int mtu;
+
public DhcpResults() {
super();
}
@@ -57,19 +60,7 @@
serverAddress = source.serverAddress;
vendorInfo = source.vendorInfo;
leaseDuration = source.leaseDuration;
- }
- }
-
- /**
- * Updates the DHCP fields that need to be retained from
- * original DHCP request if the current renewal shows them
- * being empty.
- */
- public void updateFromDhcpRequest(DhcpResults orig) {
- if (orig == null) return;
- if (gateway == null) gateway = orig.gateway;
- if (dnsServers.size() == 0) {
- dnsServers.addAll(orig.dnsServers);
+ mtu = source.mtu;
}
}
@@ -89,6 +80,7 @@
super.clear();
vendorInfo = null;
leaseDuration = 0;
+ mtu = 0;
}
@Override
@@ -98,6 +90,7 @@
str.append(" DHCP server ").append(serverAddress);
str.append(" Vendor info ").append(vendorInfo);
str.append(" lease ").append(leaseDuration).append(" seconds");
+ if (mtu != 0) str.append(" MTU ").append(mtu);
return str.toString();
}
@@ -113,7 +106,8 @@
return super.equals((StaticIpConfiguration) obj) &&
Objects.equals(serverAddress, target.serverAddress) &&
Objects.equals(vendorInfo, target.vendorInfo) &&
- leaseDuration == target.leaseDuration;
+ leaseDuration == target.leaseDuration &&
+ mtu == target.mtu;
}
/** Implement the Parcelable interface */
@@ -134,6 +128,7 @@
public void writeToParcel(Parcel dest, int flags) {
super.writeToParcel(dest, flags);
dest.writeInt(leaseDuration);
+ dest.writeInt(mtu);
NetworkUtils.parcelInetAddress(dest, serverAddress, flags);
dest.writeString(vendorInfo);
}
@@ -141,6 +136,7 @@
private static void readFromParcel(DhcpResults dhcpResults, Parcel in) {
StaticIpConfiguration.readFromParcel(dhcpResults, in);
dhcpResults.leaseDuration = in.readInt();
+ dhcpResults.mtu = in.readInt();
dhcpResults.serverAddress = (Inet4Address) NetworkUtils.unparcelInetAddress(in);
dhcpResults.vendorInfo = in.readString();
}
diff --git a/core/java/android/net/IConnectivityMetricsLogger.aidl b/core/java/android/net/IConnectivityMetricsLogger.aidl
index 2778671..a83a019 100644
--- a/core/java/android/net/IConnectivityMetricsLogger.aidl
+++ b/core/java/android/net/IConnectivityMetricsLogger.aidl
@@ -16,15 +16,28 @@
package android.net;
+import android.app.PendingIntent;
import android.net.ConnectivityMetricsEvent;
-import android.net.IConnectivityMetricsLoggerSubscriber;
/** {@hide} */
interface IConnectivityMetricsLogger {
- void logEvent(in ConnectivityMetricsEvent event);
- void logEvents(in ConnectivityMetricsEvent[] events);
+ /**
+ * @return 0 on success
+ * <0 if error happened
+ * >0 timestamp after which new events will be accepted
+ */
+ long logEvent(in ConnectivityMetricsEvent event);
+ long logEvents(in ConnectivityMetricsEvent[] events);
- boolean subscribe(in IConnectivityMetricsLoggerSubscriber subscriber);
- void unsubscribe(in IConnectivityMetricsLoggerSubscriber subscriber);
+ /**
+ * @param reference of the last event previously returned. The function will return
+ * events following it.
+ * If 0 then all events will be returned.
+ * After the function call it will contain reference of the last event.
+ */
+ ConnectivityMetricsEvent[] getEvents(inout ConnectivityMetricsEvent.Reference reference);
+
+ boolean register(in PendingIntent newEventsIntent);
+ void unregister(in PendingIntent newEventsIntent);
}
diff --git a/core/java/android/net/NetworkPolicyManager.java b/core/java/android/net/NetworkPolicyManager.java
index 8738424..e464a4a 100644
--- a/core/java/android/net/NetworkPolicyManager.java
+++ b/core/java/android/net/NetworkPolicyManager.java
@@ -57,6 +57,10 @@
public static final int RULE_REJECT_METERED = 1;
/** Reject traffic on all networks. */
public static final int RULE_REJECT_ALL = 2;
+ /** Allow traffic on metered networks. */
+ public static final int RULE_ALLOW_METERED = 3;
+ /** Temporarily allow traffic on metered networks because app is on foreground. */
+ public static final int RULE_TEMPORARY_ALLOW_METERED = 4;
public static final int FIREWALL_RULE_DEFAULT = 0;
public static final int FIREWALL_RULE_ALLOW = 1;
diff --git a/services/net/java/android/net/metrics/CaptivePortalCheckResultEvent.java b/core/java/android/net/metrics/CaptivePortalCheckResultEvent.java
similarity index 98%
rename from services/net/java/android/net/metrics/CaptivePortalCheckResultEvent.java
rename to core/java/android/net/metrics/CaptivePortalCheckResultEvent.java
index 163f7e40..2239a25 100644
--- a/services/net/java/android/net/metrics/CaptivePortalCheckResultEvent.java
+++ b/core/java/android/net/metrics/CaptivePortalCheckResultEvent.java
@@ -19,6 +19,9 @@
import android.os.Parcel;
import android.os.Parcelable;
+/**
+ * {@hide}
+ */
public class CaptivePortalCheckResultEvent extends IpConnectivityEvent implements Parcelable {
public static final String TAG = "CaptivePortalCheckResultEvent";
diff --git a/services/net/java/android/net/metrics/CaptivePortalStateChangeEvent.java b/core/java/android/net/metrics/CaptivePortalStateChangeEvent.java
similarity index 98%
rename from services/net/java/android/net/metrics/CaptivePortalStateChangeEvent.java
rename to core/java/android/net/metrics/CaptivePortalStateChangeEvent.java
index d0cc120..00808c1 100644
--- a/services/net/java/android/net/metrics/CaptivePortalStateChangeEvent.java
+++ b/core/java/android/net/metrics/CaptivePortalStateChangeEvent.java
@@ -19,6 +19,9 @@
import android.os.Parcel;
import android.os.Parcelable;
+/**
+ * {@hide}
+ */
public class CaptivePortalStateChangeEvent extends IpConnectivityEvent implements Parcelable {
public static final String TAG = "CaptivePortalStateChangeEvent";
diff --git a/services/net/java/android/net/metrics/ConnectivityServiceChangeEvent.java b/core/java/android/net/metrics/ConnectivityServiceChangeEvent.java
similarity index 98%
rename from services/net/java/android/net/metrics/ConnectivityServiceChangeEvent.java
rename to core/java/android/net/metrics/ConnectivityServiceChangeEvent.java
index 92b376c..c6fcb2d 100644
--- a/services/net/java/android/net/metrics/ConnectivityServiceChangeEvent.java
+++ b/core/java/android/net/metrics/ConnectivityServiceChangeEvent.java
@@ -19,6 +19,9 @@
import android.os.Parcel;
import android.os.Parcelable;
+/**
+ * {@hide}
+ */
public class ConnectivityServiceChangeEvent extends IpConnectivityEvent implements Parcelable {
public static final String TAG = "ConnectivityServiceChangeEvent";
diff --git a/services/net/java/android/net/metrics/DhcpClientEvent.java b/core/java/android/net/metrics/DhcpClientEvent.java
similarity index 98%
rename from services/net/java/android/net/metrics/DhcpClientEvent.java
rename to core/java/android/net/metrics/DhcpClientEvent.java
index 2c24034..7b44664 100644
--- a/services/net/java/android/net/metrics/DhcpClientEvent.java
+++ b/core/java/android/net/metrics/DhcpClientEvent.java
@@ -19,6 +19,9 @@
import android.os.Parcel;
import android.os.Parcelable;
+/**
+ * {@hide}
+ */
public class DhcpClientEvent extends IpConnectivityEvent implements Parcelable {
public static final String TAG = "DhcpClientEvent";
diff --git a/services/net/java/android/net/metrics/IpConnectivityEvent.java b/core/java/android/net/metrics/IpConnectivityEvent.java
similarity index 98%
rename from services/net/java/android/net/metrics/IpConnectivityEvent.java
rename to core/java/android/net/metrics/IpConnectivityEvent.java
index f277bd0..ec42890 100644
--- a/services/net/java/android/net/metrics/IpConnectivityEvent.java
+++ b/core/java/android/net/metrics/IpConnectivityEvent.java
@@ -20,6 +20,9 @@
import android.os.Parcel;
import android.os.Parcelable;
+/**
+ * {@hide}
+ */
public class IpConnectivityEvent implements Parcelable {
// IPRM = IpReachabilityMonitor
// DHCP = DhcpClient
diff --git a/services/net/java/android/net/metrics/IpReachabilityMonitorMessageEvent.java b/core/java/android/net/metrics/IpReachabilityMonitorMessageEvent.java
similarity index 98%
rename from services/net/java/android/net/metrics/IpReachabilityMonitorMessageEvent.java
rename to core/java/android/net/metrics/IpReachabilityMonitorMessageEvent.java
index a8c18d6..e71b0be 100644
--- a/services/net/java/android/net/metrics/IpReachabilityMonitorMessageEvent.java
+++ b/core/java/android/net/metrics/IpReachabilityMonitorMessageEvent.java
@@ -19,6 +19,9 @@
import android.os.Parcel;
import android.os.Parcelable;
+/**
+ * {@hide}
+ */
public class IpReachabilityMonitorMessageEvent extends IpConnectivityEvent
implements Parcelable {
public static final String TAG = "IpReachabilityMonitorMessageEvent";
diff --git a/services/net/java/android/net/metrics/IpReachabilityMonitorProbeEvent.java b/core/java/android/net/metrics/IpReachabilityMonitorProbeEvent.java
similarity index 98%
rename from services/net/java/android/net/metrics/IpReachabilityMonitorProbeEvent.java
rename to core/java/android/net/metrics/IpReachabilityMonitorProbeEvent.java
index 172cbf8..182b778 100644
--- a/services/net/java/android/net/metrics/IpReachabilityMonitorProbeEvent.java
+++ b/core/java/android/net/metrics/IpReachabilityMonitorProbeEvent.java
@@ -19,6 +19,9 @@
import android.os.Parcel;
import android.os.Parcelable;
+/**
+ * {@hide}
+ */
public class IpReachabilityMonitorProbeEvent extends IpConnectivityEvent
implements Parcelable {
public static final String TAG = "IpReachabilityMonitorProbeEvent";
diff --git a/core/java/android/net/nsd/NsdServiceInfo.java b/core/java/android/net/nsd/NsdServiceInfo.java
index 6fdb0d0..4a06fb1 100644
--- a/core/java/android/net/nsd/NsdServiceInfo.java
+++ b/core/java/android/net/nsd/NsdServiceInfo.java
@@ -16,8 +16,11 @@
package android.net.nsd;
+import android.annotation.NonNull;
import android.os.Parcelable;
import android.os.Parcel;
+import android.text.TextUtils;
+import android.util.Base64;
import android.util.Log;
import android.util.ArrayMap;
@@ -95,8 +98,99 @@
mPort = p;
}
+ /**
+ * Unpack txt information from a base-64 encoded byte array.
+ *
+ * @param rawRecords The raw base64 encoded records string read from netd.
+ *
+ * @hide
+ */
+ public void setTxtRecords(@NonNull String rawRecords) {
+ byte[] txtRecordsRawBytes = Base64.decode(rawRecords, Base64.DEFAULT);
+
+ // There can be multiple TXT records after each other. Each record has to following format:
+ //
+ // byte type required meaning
+ // ------------------- ------------------- -------- ----------------------------------
+ // 0 unsigned 8 bit yes size of record excluding this byte
+ // 1 - n ASCII but not '=' yes key
+ // n + 1 '=' optional separator of key and value
+ // n + 2 - record size uninterpreted bytes optional value
+ //
+ // Example legal records:
+ // [11, 'm', 'y', 'k', 'e', 'y', '=', 0x0, 0x4, 0x65, 0x7, 0xff]
+ // [17, 'm', 'y', 'K', 'e', 'y', 'W', 'i', 't', 'h', 'N', 'o', 'V', 'a', 'l', 'u', 'e', '=']
+ // [12, 'm', 'y', 'B', 'o', 'o', 'l', 'e', 'a', 'n', 'K', 'e', 'y']
+ //
+ // Example corrupted records
+ // [3, =, 1, 2] <- key is empty
+ // [3, 0, =, 2] <- key contains non-ASCII character. We handle this by replacing the
+ // invalid characters instead of skipping the record.
+ // [30, 'a', =, 2] <- length exceeds total left over bytes in the TXT records array, we
+ // handle this by reducing the length of the record as needed.
+ int pos = 0;
+ while (pos < txtRecordsRawBytes.length) {
+ // recordLen is an unsigned 8 bit value
+ int recordLen = txtRecordsRawBytes[pos] & 0xff;
+ pos += 1;
+
+ try {
+ if (recordLen == 0) {
+ throw new IllegalArgumentException("Zero sized txt record");
+ } else if (pos + recordLen > txtRecordsRawBytes.length) {
+ Log.w(TAG, "Corrupt record length (pos = " + pos + "): " + recordLen);
+ recordLen = txtRecordsRawBytes.length - pos;
+ }
+
+ // Decode key-value records
+ String key = null;
+ byte[] value = null;
+ int valueLen = 0;
+ for (int i = pos; i < pos + recordLen; i++) {
+ if (key == null) {
+ if (txtRecordsRawBytes[i] == '=') {
+ key = new String(txtRecordsRawBytes, pos, i - pos,
+ StandardCharsets.US_ASCII);
+ }
+ } else {
+ if (value == null) {
+ value = new byte[recordLen - key.length() - 1];
+ }
+ value[valueLen] = txtRecordsRawBytes[i];
+ valueLen++;
+ }
+ }
+
+ // If '=' was not found we have a boolean record
+ if (key == null) {
+ key = new String(txtRecordsRawBytes, pos, recordLen, StandardCharsets.US_ASCII);
+ }
+
+ if (TextUtils.isEmpty(key)) {
+ // Empty keys are not allowed (RFC6763 6.4)
+ throw new IllegalArgumentException("Invalid txt record (key is empty)");
+ }
+
+ if (getAttributes().containsKey(key)) {
+ // When we have a duplicate record, the later ones are ignored (RFC6763 6.4)
+ throw new IllegalArgumentException("Invalid txt record (duplicate key \"" + key + "\")");
+ }
+
+ setAttribute(key, value);
+ } catch (IllegalArgumentException e) {
+ Log.e(TAG, "While parsing txt records (pos = " + pos + "): " + e.getMessage());
+ }
+
+ pos += recordLen;
+ }
+ }
+
/** @hide */
public void setAttribute(String key, byte[] value) {
+ if (TextUtils.isEmpty(key)) {
+ throw new IllegalArgumentException("Key cannot be empty");
+ }
+
// Key must be printable US-ASCII, excluding =.
for (int i = 0; i < key.length(); ++i) {
char character = key.charAt(i);
@@ -177,10 +271,10 @@
}
/** @hide */
- public byte[] getTxtRecord() {
+ public @NonNull byte[] getTxtRecord() {
int txtRecordSize = getTxtRecordSize();
if (txtRecordSize == 0) {
- return null;
+ return new byte[]{};
}
byte[] txtRecord = new byte[txtRecordSize];
diff --git a/core/java/android/os/BaseBundle.java b/core/java/android/os/BaseBundle.java
index 6e50155..b6c919e 100644
--- a/core/java/android/os/BaseBundle.java
+++ b/core/java/android/os/BaseBundle.java
@@ -20,6 +20,7 @@
import android.util.ArrayMap;
import android.util.Log;
import android.util.MathUtils;
+import android.util.Slog;
import java.io.Serializable;
import java.util.ArrayList;
@@ -229,7 +230,7 @@
}
if (sShouldDefuse && (mFlags & FLAG_DEFUSABLE) == 0) {
- Log.wtf(TAG, "Attempting to unparcel a Bundle while in transit; this may "
+ Slog.wtf(TAG, "Attempting to unparcel a Bundle while in transit; this may "
+ "clobber all data inside!", new Throwable());
}
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index be82d56a..c452837 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -212,6 +212,7 @@
private static final String WIFI_CONTROLLER_DATA = "wfcd";
private static final String GLOBAL_BLUETOOTH_CONTROLLER_DATA = "gble";
private static final String BLUETOOTH_CONTROLLER_DATA = "ble";
+ private static final String BLUETOOTH_MISC_DATA = "blem";
private static final String MISC_DATA = "m";
private static final String GLOBAL_NETWORK_DATA = "gn";
private static final String GLOBAL_MODEM_CONTROLLER_DATA = "gmcd";
@@ -447,19 +448,41 @@
public abstract Timer getForegroundActivityTimer();
public abstract Timer getBluetoothScanTimer();
- // Time this uid has any processes in the top state.
+ // Note: the following times are disjoint. They can be added together to find the
+ // total time a uid has had any processes running at all.
+
+ /**
+ * Time this uid has any processes in the top state (or above such as persistent).
+ */
public static final int PROCESS_STATE_TOP = 0;
- // Time this uid has any process with a started out bound foreground service.
+ /**
+ * Time this uid has any process with a started out bound foreground service, but
+ * none in the "top" state.
+ */
public static final int PROCESS_STATE_FOREGROUND_SERVICE = 1;
- // Time this uid has any process that is top while the device is sleeping.
+ /**
+ * Time this uid has any process that is top while the device is sleeping, but none
+ * in the "foreground service" or better state.
+ */
public static final int PROCESS_STATE_TOP_SLEEPING = 2;
- // Time this uid has any process in an active foreground state.
+ /**
+ * Time this uid has any process in an active foreground state, but none in the
+ * "top sleeping" or better state.
+ */
public static final int PROCESS_STATE_FOREGROUND = 3;
- // Time this uid has any process in an active background state.
+ /**
+ * Time this uid has any process in an active background state, but none in the
+ * "foreground" or better state.
+ */
public static final int PROCESS_STATE_BACKGROUND = 4;
- // Time this uid has any processes running at all.
+ /**
+ * Time this uid has any processes that are sitting around cached, not in one of the
+ * other active states.
+ */
public static final int PROCESS_STATE_CACHED = 5;
- // Total number of process states we track.
+ /**
+ * Total number of process states we track.
+ */
public static final int NUM_PROCESS_STATE = 6;
static final String[] PROCESS_STATE_NAMES = {
@@ -3071,6 +3094,15 @@
dumpControllerActivityLine(pw, uid, category, WIFI_CONTROLLER_DATA,
u.getWifiControllerActivity(), which);
+ // Dump Bluetooth scan data, per UID.
+ final long bleScanTimeUs = u.getBluetoothScanTimer().getTotalTimeLocked(
+ rawRealtime, which);
+ final int bleScanCount = u.getBluetoothScanTimer().getCountLocked(which);
+ if (bleScanTimeUs != 0 || bleScanCount != 0) {
+ dumpLine(pw, uid, category, BLUETOOTH_MISC_DATA,
+ bleScanTimeUs / 1000, bleScanCount);
+ }
+
dumpControllerActivityLine(pw, uid, category, BLUETOOTH_CONTROLLER_DATA,
u.getBluetoothControllerActivity(), which);
diff --git a/core/java/android/os/Bundle.java b/core/java/android/os/Bundle.java
index 05dd48b..1128074 100644
--- a/core/java/android/os/Bundle.java
+++ b/core/java/android/os/Bundle.java
@@ -208,6 +208,18 @@
}
/**
+ * Removes any entry with the given key from the mapping of this Bundle.
+ *
+ * @param key a String key
+ */
+ public void remove(String key) {
+ super.remove(key);
+ if ((mFlags & FLAG_HAS_FDS) != 0) {
+ mFlags &= ~FLAG_HAS_FDS_KNOWN;
+ }
+ }
+
+ /**
* Inserts all mappings from the given Bundle into this Bundle.
*
* @param bundle a Bundle
@@ -288,6 +300,8 @@
if (fdFound) {
mFlags |= FLAG_HAS_FDS;
+ } else {
+ mFlags &= ~FLAG_HAS_FDS;
}
mFlags |= FLAG_HAS_FDS_KNOWN;
}
@@ -315,6 +329,8 @@
mMap.removeAt(i);
}
}
+ mFlags |= FLAG_HAS_FDS_KNOWN;
+ mFlags &= ~FLAG_HAS_FDS;
}
/**
diff --git a/core/java/android/os/HardwarePropertiesManager.java b/core/java/android/os/HardwarePropertiesManager.java
index f13e5b5..9d362d6 100644
--- a/core/java/android/os/HardwarePropertiesManager.java
+++ b/core/java/android/os/HardwarePropertiesManager.java
@@ -48,7 +48,8 @@
*/
@Retention(RetentionPolicy.SOURCE)
@IntDef({
- TEMPERATURE_CURRENT, TEMPERATURE_THROTTLING, TEMPERATURE_SHUTDOWN
+ TEMPERATURE_CURRENT, TEMPERATURE_THROTTLING, TEMPERATURE_SHUTDOWN,
+ TEMPERATURE_THROTTLING_BELOW_VR_MIN
})
public @interface TemperatureSource {}
@@ -77,6 +78,12 @@
/** Get shutdown temperature threshold. */
public static final int TEMPERATURE_SHUTDOWN = 2;
+ /**
+ * Get throttling temperature threshold above which minimum clockrates for VR mode will not be
+ * met.
+ */
+ public static final int TEMPERATURE_THROTTLING_BELOW_VR_MIN = 3;
+
/** Undefined temperature constant. */
public static final float UNDEFINED_TEMPERATURE = -Float.MAX_VALUE;
@@ -96,7 +103,8 @@
* {@link #DEVICE_TEMPERATURE_GPU}, {@link #DEVICE_TEMPERATURE_BATTERY} or {@link
* #DEVICE_TEMPERATURE_SKIN}.
* @param source source of requested device temperature, one of {@link #TEMPERATURE_CURRENT},
- * {@link #TEMPERATURE_THROTTLING} or {@link #TEMPERATURE_SHUTDOWN}.
+ * {@link #TEMPERATURE_THROTTLING}, {@link #TEMPERATURE_THROTTLING_BELOW_VR_MIN} or
+ * {@link #TEMPERATURE_SHUTDOWN}.
* @return an array of requested float device temperatures. Temperature equals to
* {@link #UNDEFINED_TEMPERATURE} if undefined.
* Empty if platform doesn't provide the queried temperature.
@@ -115,6 +123,7 @@
case TEMPERATURE_CURRENT:
case TEMPERATURE_THROTTLING:
case TEMPERATURE_SHUTDOWN:
+ case TEMPERATURE_THROTTLING_BELOW_VR_MIN:
try {
return mService.getDeviceTemperatures(mContext.getOpPackageName(), type,
source);
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index 8bc903b..92edc62 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -221,11 +221,9 @@
/**
* Wake lock level: Enables Sustained Performance Mode.
* <p>
- * This is used by Gaming and VR applications to ensure the device provides
+ * This is used by Gaming and VR applications to ensure the device
* will provide consistent performance over a large amount of time.
* </p>
- *
- * {@hide}
*/
public static final int SUSTAINED_PERFORMANCE_WAKE_LOCK = 0x00000100;
@@ -1033,6 +1031,16 @@
}
/**
+ * Returns True if the device supports Sustained Performance Mode.
+ * Applications Should check if the device supports this mode, before
+ * using {@link #SUSTAINED_PERFORMANCE_WAKE_LOCK}.
+ */
+ public boolean isSustainedPerformanceModeSupported() {
+ return mContext.getResources().getBoolean(
+ com.android.internal.R.bool.config_sustainedPerformanceModeSupported);
+ }
+
+ /**
* Intent that is broadcast when the state of {@link #isPowerSaveMode()} changes.
* This broadcast is only sent to registered receivers.
*/
diff --git a/core/java/android/os/UpdateEngine.java b/core/java/android/os/UpdateEngine.java
index 80e6146..bf03cce 100644
--- a/core/java/android/os/UpdateEngine.java
+++ b/core/java/android/os/UpdateEngine.java
@@ -87,7 +87,7 @@
}
@SystemApi
- public boolean bind(final UpdateEngineCallback callback, final Handler handler) throws RemoteException {
+ public boolean bind(final UpdateEngineCallback callback, final Handler handler) {
IUpdateEngineCallback updateEngineCallback = new IUpdateEngineCallback.Stub() {
@Override
public void onStatusUpdate(final int status, final float percent) {
@@ -118,31 +118,60 @@
}
};
- return mUpdateEngine.bind(updateEngineCallback);
+ try {
+ return mUpdateEngine.bind(updateEngineCallback);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
}
@SystemApi
- public boolean bind(final UpdateEngineCallback callback) throws RemoteException {
+ public boolean bind(final UpdateEngineCallback callback) {
return bind(callback, null);
}
@SystemApi
- public void applyPayload(String url, long offset, long size, String[] headerKeyValuePairs) throws RemoteException {
- mUpdateEngine.applyPayload(url, offset, size, headerKeyValuePairs);
+ public void applyPayload(String url, long offset, long size, String[] headerKeyValuePairs) {
+ try {
+ mUpdateEngine.applyPayload(url, offset, size, headerKeyValuePairs);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
}
@SystemApi
- public void cancel() throws RemoteException {
- mUpdateEngine.cancel();
+ public void cancel() {
+ try {
+ mUpdateEngine.cancel();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
}
@SystemApi
- public void suspend() throws RemoteException {
- mUpdateEngine.suspend();
+ public void suspend() {
+ try {
+ mUpdateEngine.suspend();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
}
@SystemApi
- public void resume() throws RemoteException {
- mUpdateEngine.resume();
+ public void resume() {
+ try {
+ mUpdateEngine.resume();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ @SystemApi
+ public void resetStatus() {
+ try {
+ mUpdateEngine.resetStatus();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
}
}
diff --git a/core/java/android/os/health/TimerStat.java b/core/java/android/os/health/TimerStat.java
index fc51b60..b9d8874 100644
--- a/core/java/android/os/health/TimerStat.java
+++ b/core/java/android/os/health/TimerStat.java
@@ -27,7 +27,7 @@
* object to be constructed, even internally, but the getTimers method on
* {@link android.os.health.HealthStats} does require TimerStat objects.
*/
-public class TimerStat implements Parcelable {
+public final class TimerStat implements Parcelable {
private int mCount;
private long mTime;
diff --git a/core/java/android/os/storage/StorageVolume.java b/core/java/android/os/storage/StorageVolume.java
index c028e15..7b0d2a4 100644
--- a/core/java/android/os/storage/StorageVolume.java
+++ b/core/java/android/os/storage/StorageVolume.java
@@ -315,27 +315,34 @@
* To gain access to descendants (child, grandchild, etc) documents, use
* {@link DocumentsContract#buildDocumentUriUsingTree(Uri, String)}, or
* {@link DocumentsContract#buildChildDocumentsUriUsingTree(Uri, String)} with the returned URI.
- *
- * <b>If your application only needs to store internal data, consider using
+ * <p>
+ * If your application only needs to store internal data, consider using
* {@link Context#getExternalFilesDirs(String) Context.getExternalFilesDirs},
- * {@link Context#getExternalCacheDirs()}, or
- * {@link Context#getExternalMediaDirs()}, which require no permissions to read or write.
+ * {@link Context#getExternalCacheDirs()}, or {@link Context#getExternalMediaDirs()}, which
+ * require no permissions to read or write.
+ * <p>
+ * Access to the entire volume is only available for non-primary volumes (for the primary
+ * volume, apps can use the {@link android.Manifest.permission#READ_EXTERNAL_STORAGE} and
+ * {@link android.Manifest.permission#WRITE_EXTERNAL_STORAGE} permissions) and should be used
+ * with caution, since users are more likely to deny access when asked for entire volume access
+ * rather than specific directories.
*
- * <strong>NOTE: </strong>requesting access to the entire volume is not recommended and it will
- * result in a stronger message displayed to the user, which may cause the user to reject
- * the request.
- *
- * @param directoryName must be one of
- * {@link Environment#DIRECTORY_MUSIC}, {@link Environment#DIRECTORY_PODCASTS},
- * {@link Environment#DIRECTORY_RINGTONES}, {@link Environment#DIRECTORY_ALARMS},
- * {@link Environment#DIRECTORY_NOTIFICATIONS}, {@link Environment#DIRECTORY_PICTURES},
- * {@link Environment#DIRECTORY_MOVIES}, {@link Environment#DIRECTORY_DOWNLOADS},
- * {@link Environment#DIRECTORY_DCIM}, or {@link Environment#DIRECTORY_DOCUMENTS}, or
- * {code null} to request access to the entire volume.
- *
+ * @param directoryName must be one of {@link Environment#DIRECTORY_MUSIC},
+ * {@link Environment#DIRECTORY_PODCASTS}, {@link Environment#DIRECTORY_RINGTONES},
+ * {@link Environment#DIRECTORY_ALARMS}, {@link Environment#DIRECTORY_NOTIFICATIONS},
+ * {@link Environment#DIRECTORY_PICTURES}, {@link Environment#DIRECTORY_MOVIES},
+ * {@link Environment#DIRECTORY_DOWNLOADS}, {@link Environment#DIRECTORY_DCIM}, or
+ * {@link Environment#DIRECTORY_DOCUMENTS}, or {code null} to request access to the
+ * entire volume.
+ * @return intent to request access, or {@code null} if the requested directory is invalid for
+ * that volume.
* @see DocumentsContract
*/
- public Intent createAccessIntent(String directoryName) {
+ public @Nullable Intent createAccessIntent(String directoryName) {
+ if ((isPrimary() && directoryName == null) ||
+ (directoryName != null && !Environment.isStandardDirectory(directoryName))) {
+ return null;
+ }
final Intent intent = new Intent(ACTION_OPEN_EXTERNAL_DIRECTORY);
intent.putExtra(EXTRA_STORAGE_VOLUME, this);
intent.putExtra(EXTRA_DIRECTORY_NAME, directoryName);
diff --git a/core/java/android/preference/Preference.java b/core/java/android/preference/Preference.java
index d41bc07..b1cad05 100644
--- a/core/java/android/preference/Preference.java
+++ b/core/java/android/preference/Preference.java
@@ -1184,10 +1184,9 @@
/**
* Called when the Preference hierarchy has been attached to the
- * {@link PreferenceActivity} or {@link PreferenceFragment}. This can
- * also be called when this Preference has been attached to a group
- * that was already attached to the {@link PreferenceActivity} or
- * {@link PreferenceFragment}.
+ * {@link PreferenceActivity}. This can also be called when this
+ * Preference has been attached to a group that was already attached
+ * to the {@link PreferenceActivity}.
*/
protected void onAttachedToActivity() {
// At this point, the hierarchy that this preference is in is connected
@@ -1195,16 +1194,6 @@
registerDependency();
}
- /**
- * Called when the Preference hierarchy has been detached from the
- * {@link PreferenceActivity} or {@link PreferenceFragment}. This can
- * also be called when this Preference has been removed from a group
- * that was already attached to the {@link PreferenceActivity} or
- * {@link PreferenceFragment}.
- */
- protected void onDetachedFromActivity() {
- }
-
private void registerDependency() {
if (TextUtils.isEmpty(mDependencyKey)) return;
diff --git a/core/java/android/preference/PreferenceGroup.java b/core/java/android/preference/PreferenceGroup.java
index 13c3661..f17506b 100644
--- a/core/java/android/preference/PreferenceGroup.java
+++ b/core/java/android/preference/PreferenceGroup.java
@@ -186,11 +186,7 @@
private boolean removePreferenceInt(Preference preference) {
synchronized(this) {
preference.onPrepareForRemoval();
- boolean success = mPreferenceList.remove(preference);
- if (mAttachedToActivity) {
- preference.onDetachedFromActivity();
- }
- return success;
+ return mPreferenceList.remove(preference);
}
}
@@ -266,7 +262,7 @@
protected boolean isOnSameScreenAsChildren() {
return true;
}
-
+
@Override
protected void onAttachedToActivity() {
super.onAttachedToActivity();
@@ -283,17 +279,11 @@
}
@Override
- protected void onDetachedFromActivity() {
- super.onDetachedFromActivity();
-
+ protected void onPrepareForRemoval() {
+ super.onPrepareForRemoval();
+
// We won't be attached to the activity anymore
mAttachedToActivity = false;
-
- // Dispatch to all contained preferences
- final int preferenceCount = getPreferenceCount();
- for (int i = 0; i < preferenceCount; i++) {
- getPreference(i).onDetachedFromActivity();
- }
}
@Override
diff --git a/core/java/android/preference/PreferenceManager.java b/core/java/android/preference/PreferenceManager.java
index 73174e3..1a6b06f 100644
--- a/core/java/android/preference/PreferenceManager.java
+++ b/core/java/android/preference/PreferenceManager.java
@@ -519,9 +519,6 @@
*/
boolean setPreferences(PreferenceScreen preferenceScreen) {
if (preferenceScreen != mPreferenceScreen) {
- if (mPreferenceScreen != null) {
- mPreferenceScreen.onDetachedFromActivity();
- }
mPreferenceScreen = preferenceScreen;
return true;
}
@@ -830,11 +827,7 @@
*/
void dispatchActivityDestroy() {
List<OnActivityDestroyListener> list = null;
-
- if (mPreferenceScreen != null) {
- mPreferenceScreen.onDetachedFromActivity();
- mPreferenceScreen = null;
- }
+
synchronized (this) {
if (mActivityDestroyListeners != null) {
list = new ArrayList<OnActivityDestroyListener>(mActivityDestroyListeners);
diff --git a/core/java/android/print/IPrintManager.aidl b/core/java/android/print/IPrintManager.aidl
index 5eb8cc2..d7c267b 100644
--- a/core/java/android/print/IPrintManager.aidl
+++ b/core/java/android/print/IPrintManager.aidl
@@ -24,9 +24,11 @@
import android.print.PrintJobId;
import android.print.IPrintJobStateChangeListener;
import android.print.IPrintServicesChangeListener;
+import android.printservice.recommendation.IRecommendationsChangeListener;
import android.print.PrinterId;
import android.print.PrintJobInfo;
import android.print.PrintAttributes;
+import android.printservice.recommendation.RecommendationInfo;
import android.printservice.PrintServiceInfo;
/**
@@ -73,7 +75,6 @@
* Get the print services.
*
* @param selectionFlags flags selecting which services to get
- * @param selectedService if not null, the id of the print service to get
* @param userId the id of the user requesting the services
*
* @return the list of selected print services.
@@ -89,6 +90,37 @@
*/
void setPrintServiceEnabled(in ComponentName service, boolean isEnabled, int userId);
+ /**
+ * Listen for changes to the print service recommendations.
+ *
+ * @param listener the listener to add
+ * @param userId the id of the user listening
+ *
+ * @see android.print.PrintManager#getPrintServiceRecommendations
+ */
+ void addPrintServiceRecommendationsChangeListener(in IRecommendationsChangeListener listener,
+ int userId);
+
+ /**
+ * Stop listening for changes to the print service recommendations.
+ *
+ * @param listener the listener to remove
+ * @param userId the id of the user requesting the removal
+ *
+ * @see android.print.PrintManager#getPrintServiceRecommendations
+ */
+ void removePrintServiceRecommendationsChangeListener(in IRecommendationsChangeListener listener,
+ int userId);
+
+ /**
+ * Get the print service recommendations.
+ *
+ * @param userId the id of the user requesting the recommendations
+ *
+ * @return the list of selected print services.
+ */
+ List<RecommendationInfo> getPrintServiceRecommendations(int userId);
+
void createPrinterDiscoverySession(in IPrinterDiscoveryObserver observer, int userId);
void startPrinterDiscovery(in IPrinterDiscoveryObserver observer,
in List<PrinterId> priorityList, int userId);
diff --git a/core/java/android/print/PageRange.java b/core/java/android/print/PageRange.java
index 57c7718..2941283 100644
--- a/core/java/android/print/PageRange.java
+++ b/core/java/android/print/PageRange.java
@@ -32,6 +32,9 @@
*/
public static final PageRange ALL_PAGES = new PageRange(0, Integer.MAX_VALUE);
+ /** @hide */
+ public static final PageRange[] ALL_PAGES_ARRAY = new PageRange[]{PageRange.ALL_PAGES};
+
private final int mStart;
private final int mEnd;
diff --git a/core/java/android/print/PrintAttributes.java b/core/java/android/print/PrintAttributes.java
index e9c196d..721c94e 100644
--- a/core/java/android/print/PrintAttributes.java
+++ b/core/java/android/print/PrintAttributes.java
@@ -20,6 +20,7 @@
import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.StringRes;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.res.Resources.NotFoundException;
@@ -31,6 +32,7 @@
import android.util.Log;
import com.android.internal.R;
+import com.android.internal.util.Preconditions;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -49,7 +51,7 @@
@IntDef(flag = true, value = {
COLOR_MODE_MONOCHROME, COLOR_MODE_COLOR
})
- public @interface ColorMode {
+ @interface ColorMode {
}
/** Color mode: Monochrome color scheme, for example one color is used. */
public static final int COLOR_MODE_MONOCHROME = 1 << 0;
@@ -64,7 +66,7 @@
@IntDef(flag = true, value = {
DUPLEX_MODE_NONE, DUPLEX_MODE_LONG_EDGE, DUPLEX_MODE_SHORT_EDGE
})
- public @interface DuplexMode {
+ @interface DuplexMode {
}
/** Duplex mode: No duplexing. */
public static final int DUPLEX_MODE_NONE = 1 << 0;
@@ -76,23 +78,29 @@
private static final int VALID_DUPLEX_MODES =
DUPLEX_MODE_NONE | DUPLEX_MODE_LONG_EDGE | DUPLEX_MODE_SHORT_EDGE;
- private MediaSize mMediaSize;
- private Resolution mResolution;
- private Margins mMinMargins;
+ private @Nullable MediaSize mMediaSize;
+ private @Nullable Resolution mResolution;
+ private @Nullable Margins mMinMargins;
- private int mColorMode;
- private int mDuplexMode;
+ private @IntRange(from = 0) int mColorMode;
+ private @IntRange(from = 0) int mDuplexMode;
PrintAttributes() {
/* hide constructor */
}
private PrintAttributes(@NonNull Parcel parcel) {
- mMediaSize = (parcel.readInt() == 1) ? MediaSize.createFromParcel(parcel) : null;
- mResolution = (parcel.readInt() == 1) ? Resolution.createFromParcel(parcel) : null;
- mMinMargins = (parcel.readInt() == 1) ? Margins.createFromParcel(parcel) : null;
+ mMediaSize = (parcel.readInt() == 1) ? MediaSize.createFromParcel(parcel) : null;
+ mResolution = (parcel.readInt() == 1) ? Resolution.createFromParcel(parcel) : null;
+ mMinMargins = (parcel.readInt() == 1) ? Margins.createFromParcel(parcel) : null;
mColorMode = parcel.readInt();
+ if (mColorMode != 0) {
+ enforceValidColorMode(mColorMode);
+ }
mDuplexMode = parcel.readInt();
+ if (mDuplexMode != 0) {
+ enforceValidDuplexMode(mDuplexMode);
+ }
}
/**
@@ -179,7 +187,7 @@
* @see #COLOR_MODE_COLOR
* @see #COLOR_MODE_MONOCHROME
*/
- public @ColorMode int getColorMode() {
+ public @IntRange(from = 0) int getColorMode() {
return mColorMode;
}
@@ -214,13 +222,13 @@
/**
* Gets the duplex mode.
*
- * @return The duplex mode.
+ * @return The duplex mode or zero if not set.
*
* @see #DUPLEX_MODE_NONE
* @see #DUPLEX_MODE_LONG_EDGE
* @see #DUPLEX_MODE_SHORT_EDGE
*/
- public @DuplexMode int getDuplexMode() {
+ public @IntRange(from = 0) int getDuplexMode() {
return mDuplexMode;
}
@@ -448,7 +456,7 @@
private static final String LOG_TAG = "MediaSize";
private static final Map<String, MediaSize> sIdToMediaSizeMap =
- new ArrayMap<String, MediaSize>();
+ new ArrayMap<>();
/**
* Unknown media size in portrait mode.
@@ -781,15 +789,15 @@
new MediaSize("JPN_YOU4", "android",
R.string.mediasize_japanese_you4, 4134, 9252);
- private final String mId;
+ private final @NonNull String mId;
/**@hide */
- public final String mLabel;
+ public final @NonNull String mLabel;
/**@hide */
- public final String mPackageName;
+ public final @Nullable String mPackageName;
/**@hide */
- public final int mLabelResId;
- private final int mWidthMils;
- private final int mHeightMils;
+ public final @StringRes int mLabelResId;
+ private final @IntRange(from = 1) int mWidthMils;
+ private final @IntRange(from = 1) int mHeightMils;
/**
* Creates a new instance.
@@ -808,29 +816,7 @@
*/
public MediaSize(String id, String packageName, int labelResId,
int widthMils, int heightMils) {
- if (TextUtils.isEmpty(id)) {
- throw new IllegalArgumentException("id cannot be empty.");
- }
- if (TextUtils.isEmpty(packageName)) {
- throw new IllegalArgumentException("packageName cannot be empty.");
- }
- if (labelResId <= 0) {
- throw new IllegalArgumentException("labelResId must be greater than zero.");
- }
- if (widthMils <= 0) {
- throw new IllegalArgumentException("widthMils "
- + "cannot be less than or equal to zero.");
- }
- if (heightMils <= 0) {
- throw new IllegalArgumentException("heightMils "
- + "cannot be less than or euqual to zero.");
- }
- mPackageName = packageName;
- mId = id;
- mLabelResId = labelResId;
- mWidthMils = widthMils;
- mHeightMils = heightMils;
- mLabel = null;
+ this(id, null, packageName, widthMils, heightMils, labelResId);
// Build this mapping only for predefined media sizes.
sIdToMediaSizeMap.put(mId, this);
@@ -851,26 +837,7 @@
*/
public MediaSize(@NonNull String id, @NonNull String label,
@IntRange(from = 1) int widthMils, @IntRange(from = 1) int heightMils) {
- if (TextUtils.isEmpty(id)) {
- throw new IllegalArgumentException("id cannot be empty.");
- }
- if (TextUtils.isEmpty(label)) {
- throw new IllegalArgumentException("label cannot be empty.");
- }
- if (widthMils <= 0) {
- throw new IllegalArgumentException("widthMils "
- + "cannot be less than or equal to zero.");
- }
- if (heightMils <= 0) {
- throw new IllegalArgumentException("heightMils "
- + "cannot be less than or euqual to zero.");
- }
- mId = id;
- mLabel = label;
- mWidthMils = widthMils;
- mHeightMils = heightMils;
- mLabelResId = 0;
- mPackageName = null;
+ this(id, label, null, widthMils, heightMils, 0);
}
/**
@@ -890,15 +857,37 @@
return definedMediaSizes;
}
- /** @hide */
- public MediaSize(String id, String label, String packageName,
- int widthMils, int heightMils, int labelResId) {
+ /**
+ * Creates a new instance.
+ *
+ * @param id The unique media size id. It is unique amongst other media sizes
+ * supported by the printer.
+ * @param label The <strong>localized</strong> human readable label.
+ * @param packageName The name of the creating package.
+ * @param widthMils The width in mils (thousands of an inch).
+ * @param heightMils The height in mils (thousands of an inch).
+ * @param labelResId The resource if of a human readable label.
+ *
+ * @throws IllegalArgumentException If the id is empty or the label is unset
+ * or the widthMils is less than or equal to zero or the heightMils is less
+ * than or equal to zero.
+ *
+ * @hide
+ */
+ public MediaSize(String id, String label, String packageName, int widthMils, int heightMils,
+ int labelResId) {
mPackageName = packageName;
- mId = id;
+ mId = Preconditions.checkStringNotEmpty(id, "id cannot be empty.");
mLabelResId = labelResId;
- mWidthMils = widthMils;
- mHeightMils = heightMils;
+ mWidthMils = Preconditions.checkArgumentPositive(widthMils, "widthMils cannot be " +
+ "less than or equal to zero.");
+ mHeightMils = Preconditions.checkArgumentPositive(heightMils, "heightMils cannot be " +
+ "less than or equal to zero.");
mLabel = label;
+
+ // The label has to be either a string ot a StringRes
+ Preconditions.checkArgument(!TextUtils.isEmpty(label) !=
+ (!TextUtils.isEmpty(packageName) && labelResId != 0), "label cannot be empty.");
}
/**
@@ -926,10 +915,7 @@
try {
return packageManager.getResourcesForApplication(
mPackageName).getString(mLabelResId);
- } catch (NotFoundException nfe) {
- Log.w(LOG_TAG, "Could not load resouce" + mLabelResId
- + " from package " + mPackageName);
- } catch (NameNotFoundException nnfee) {
+ } catch (NotFoundException | NameNotFoundException e) {
Log.w(LOG_TAG, "Could not load resouce" + mLabelResId
+ " from package " + mPackageName);
}
@@ -1084,10 +1070,10 @@
* the one with 300 DPI resolution.
*/
public static final class Resolution {
- private final String mId;
- private final String mLabel;
- private final int mHorizontalDpi;
- private final int mVerticalDpi;
+ private final @NonNull String mId;
+ private final @NonNull String mLabel;
+ private final @IntRange(from = 1) int mHorizontalDpi;
+ private final @IntRange(from = 1) int mVerticalDpi;
/**
* Creates a new instance.
@@ -1244,8 +1230,7 @@
* @param rightMils The right margin in mils (thousands of an inch).
* @param bottomMils The bottom margin in mils (thousands of an inch).
*/
- public Margins(@IntRange(from = 0) int leftMils, @IntRange(from = 0) int topMils,
- @IntRange(from = 0) int rightMils, @IntRange(from = 0) int bottomMils) {
+ public Margins(int leftMils, int topMils, int rightMils, int bottomMils) {
mTopMils = topMils;
mLeftMils = leftMils;
mRightMils = rightMils;
@@ -1257,7 +1242,7 @@
*
* @return The left margin.
*/
- public @IntRange(from = 0) int getLeftMils() {
+ public int getLeftMils() {
return mLeftMils;
}
@@ -1266,7 +1251,7 @@
*
* @return The top margin.
*/
- public @IntRange(from = 0) int getTopMils() {
+ public int getTopMils() {
return mTopMils;
}
@@ -1275,7 +1260,7 @@
*
* @return The right margin.
*/
- public @IntRange(from = 0) int getRightMils() {
+ public int getRightMils() {
return mRightMils;
}
@@ -1284,7 +1269,7 @@
*
* @return The bottom margin.
*/
- public @IntRange(from = 0) int getBottomMils() {
+ public int getBottomMils() {
return mBottomMils;
}
diff --git a/core/java/android/print/PrintDocumentInfo.java b/core/java/android/print/PrintDocumentInfo.java
index db3b6f4..bec6f29 100644
--- a/core/java/android/print/PrintDocumentInfo.java
+++ b/core/java/android/print/PrintDocumentInfo.java
@@ -22,6 +22,7 @@
import android.os.Parcel;
import android.os.Parcelable;
import android.text.TextUtils;
+import com.android.internal.util.Preconditions;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -114,8 +115,8 @@
*/
public static final int CONTENT_TYPE_PHOTO = 1;
- private String mName;
- private int mPageCount;
+ private @NonNull String mName;
+ private @IntRange(from = -1) int mPageCount;
private int mContentType;
private long mDataSize;
@@ -144,10 +145,11 @@
* @param parcel Data from which to initialize.
*/
private PrintDocumentInfo(Parcel parcel) {
- mName = parcel.readString();
+ mName = Preconditions.checkStringNotEmpty(parcel.readString());
mPageCount = parcel.readInt();
+ Preconditions.checkArgument(mPageCount == PAGE_COUNT_UNKNOWN || mPageCount > 0);
mContentType = parcel.readInt();
- mDataSize = parcel.readLong();
+ mDataSize = Preconditions.checkArgumentNonnegative(parcel.readLong());
}
/**
@@ -180,7 +182,7 @@
* @see #CONTENT_TYPE_DOCUMENT
* @see #CONTENT_TYPE_PHOTO
*/
- public @ContentType int getContentType() {
+ public int getContentType() {
return mContentType;
}
@@ -262,13 +264,13 @@
builder.append("PrintDocumentInfo{");
builder.append("name=").append(mName);
builder.append(", pageCount=").append(mPageCount);
- builder.append(", contentType=").append(contentTyepToString(mContentType));
+ builder.append(", contentType=").append(contentTypeToString(mContentType));
builder.append(", dataSize=").append(mDataSize);
builder.append("}");
return builder.toString();
}
- private String contentTyepToString(int contentType) {
+ private String contentTypeToString(int contentType) {
switch (contentType) {
case CONTENT_TYPE_DOCUMENT: {
return "CONTENT_TYPE_DOCUMENT";
diff --git a/core/java/android/print/PrintManager.java b/core/java/android/print/PrintManager.java
index 25fc968..71f0bd6 100644
--- a/core/java/android/print/PrintManager.java
+++ b/core/java/android/print/PrintManager.java
@@ -36,12 +36,15 @@
import android.print.PrintDocumentAdapter.LayoutResultCallback;
import android.print.PrintDocumentAdapter.WriteResultCallback;
import android.printservice.PrintServiceInfo;
+import android.printservice.recommendation.IRecommendationsChangeListener;
+import android.printservice.recommendation.RecommendationInfo;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.Log;
import com.android.internal.os.SomeArgs;
+import com.android.internal.util.Preconditions;
import libcore.io.IoUtils;
import java.lang.ref.WeakReference;
@@ -113,6 +116,7 @@
private static final int MSG_NOTIFY_PRINT_JOB_STATE_CHANGED = 1;
private static final int MSG_NOTIFY_PRINT_SERVICES_CHANGED = 2;
+ private static final int MSG_NOTIFY_PRINT_SERVICE_RECOMMENDATIONS_CHANGED = 3;
/**
* Package name of print spooler.
@@ -202,6 +206,9 @@
mPrintJobStateChangeListeners;
private Map<PrintServicesChangeListener, PrintServicesChangeListenerWrapper>
mPrintServicesChangeListeners;
+ private Map<PrintServiceRecommendationsChangeListener,
+ PrintServiceRecommendationsChangeListenerWrapper>
+ mPrintServiceRecommendationsChangeListeners;
/** @hide */
public interface PrintJobStateChangeListener {
@@ -223,6 +230,15 @@
public void onPrintServicesChanged();
}
+ /** @hide */
+ public interface PrintServiceRecommendationsChangeListener {
+
+ /**
+ * Callback notifying that the print service recommendations changed.
+ */
+ void onPrintServiceRecommendationsChanged();
+ }
+
/**
* Creates a new instance.
*
@@ -260,7 +276,14 @@
listener.onPrintServicesChanged();
}
} break;
-
+ case MSG_NOTIFY_PRINT_SERVICE_RECOMMENDATIONS_CHANGED: {
+ PrintServiceRecommendationsChangeListenerWrapper wrapper =
+ (PrintServiceRecommendationsChangeListenerWrapper) message.obj;
+ PrintServiceRecommendationsChangeListener listener = wrapper.getListener();
+ if (listener != null) {
+ listener.onPrintServiceRecommendationsChanged();
+ }
+ } break;
}
}
};
@@ -539,13 +562,14 @@
* @see android.print.PrintManager#getPrintServices
*/
void addPrintServicesChangeListener(@NonNull PrintServicesChangeListener listener) {
+ Preconditions.checkNotNull(listener);
+
if (mService == null) {
Log.w(LOG_TAG, "Feature android.software.print not available");
return;
}
if (mPrintServicesChangeListeners == null) {
- mPrintServicesChangeListeners = new ArrayMap<PrintServicesChangeListener,
- PrintServicesChangeListenerWrapper>();
+ mPrintServicesChangeListeners = new ArrayMap<>();
}
PrintServicesChangeListenerWrapper wrappedListener =
new PrintServicesChangeListenerWrapper(listener, mHandler);
@@ -565,6 +589,8 @@
* @see android.print.PrintManager#getPrintServices
*/
void removePrintServicesChangeListener(@NonNull PrintServicesChangeListener listener) {
+ Preconditions.checkNotNull(listener);
+
if (mService == null) {
Log.w(LOG_TAG, "Feature android.software.print not available");
return;
@@ -588,7 +614,6 @@
}
}
-
/**
* Gets the list of print services, but does not register for updates. The user has to register
* for updates by itself, or use {@link PrintServicesLoader}.
@@ -596,7 +621,7 @@
* @param selectionFlags flags selecting which services to get. Either
* {@link #ENABLED_SERVICES},{@link #DISABLED_SERVICES}, or both.
*
- * @return The enabled service list or an empty list.
+ * @return The print service list or an empty list.
*
* @see #addPrintServicesChangeListener(PrintServicesChangeListener)
* @see #removePrintServicesChangeListener(PrintServicesChangeListener)
@@ -604,6 +629,8 @@
* @hide
*/
public @NonNull List<PrintServiceInfo> getPrintServices(int selectionFlags) {
+ Preconditions.checkFlagsArgument(selectionFlags, ALL_SERVICES);
+
try {
List<PrintServiceInfo> services = mService.getPrintServices(selectionFlags, mUserId);
if (services != null) {
@@ -616,6 +643,92 @@
}
/**
+ * Listen for changes to the print service recommendations.
+ *
+ * @param listener the listener to add
+ *
+ * @see android.print.PrintManager#getPrintServiceRecommendations
+ */
+ void addPrintServiceRecommendationsChangeListener(
+ @NonNull PrintServiceRecommendationsChangeListener listener) {
+ Preconditions.checkNotNull(listener);
+
+ if (mService == null) {
+ Log.w(LOG_TAG, "Feature android.software.print not available");
+ return;
+ }
+ if (mPrintServiceRecommendationsChangeListeners == null) {
+ mPrintServiceRecommendationsChangeListeners = new ArrayMap<>();
+ }
+ PrintServiceRecommendationsChangeListenerWrapper wrappedListener =
+ new PrintServiceRecommendationsChangeListenerWrapper(listener, mHandler);
+ try {
+ mService.addPrintServiceRecommendationsChangeListener(wrappedListener, mUserId);
+ mPrintServiceRecommendationsChangeListeners.put(listener, wrappedListener);
+ } catch (RemoteException re) {
+ throw re.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Stop listening for changes to the print service recommendations.
+ *
+ * @param listener the listener to remove
+ *
+ * @see android.print.PrintManager#getPrintServiceRecommendations
+ */
+ void removePrintServiceRecommendationsChangeListener(
+ @NonNull PrintServiceRecommendationsChangeListener listener) {
+ Preconditions.checkNotNull(listener);
+
+ if (mService == null) {
+ Log.w(LOG_TAG, "Feature android.software.print not available");
+ return;
+ }
+ if (mPrintServiceRecommendationsChangeListeners == null) {
+ return;
+ }
+ PrintServiceRecommendationsChangeListenerWrapper wrappedListener =
+ mPrintServiceRecommendationsChangeListeners.remove(listener);
+ if (wrappedListener == null) {
+ return;
+ }
+ if (mPrintServiceRecommendationsChangeListeners.isEmpty()) {
+ mPrintServiceRecommendationsChangeListeners = null;
+ }
+ wrappedListener.destroy();
+ try {
+ mService.removePrintServiceRecommendationsChangeListener(wrappedListener, mUserId);
+ } catch (RemoteException re) {
+ throw re.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Gets the list of print service recommendations, but does not register for updates. The user
+ * has to register for updates by itself, or use {@link PrintServiceRecommendationsLoader}.
+ *
+ * @return The print service recommendations list or an empty list.
+ *
+ * @see #addPrintServiceRecommendationsChangeListener
+ * @see #removePrintServiceRecommendationsChangeListener
+ *
+ * @hide
+ */
+ public @NonNull List<RecommendationInfo> getPrintServiceRecommendations() {
+ try {
+ List<RecommendationInfo> recommendations =
+ mService.getPrintServiceRecommendations(mUserId);
+ if (recommendations != null) {
+ return recommendations;
+ }
+ } catch (RemoteException re) {
+ throw re.rethrowFromSystemServer();
+ }
+ return Collections.emptyList();
+ }
+
+ /**
* @hide
*/
public PrinterDiscoverySession createPrinterDiscoverySession() {
@@ -1242,4 +1355,37 @@
return mWeakListener.get();
}
}
+
+ /**
+ * @hide
+ */
+ public static final class PrintServiceRecommendationsChangeListenerWrapper extends
+ IRecommendationsChangeListener.Stub {
+ private final WeakReference<PrintServiceRecommendationsChangeListener> mWeakListener;
+ private final WeakReference<Handler> mWeakHandler;
+
+ public PrintServiceRecommendationsChangeListenerWrapper(
+ PrintServiceRecommendationsChangeListener listener, Handler handler) {
+ mWeakListener = new WeakReference<>(listener);
+ mWeakHandler = new WeakReference<>(handler);
+ }
+
+ @Override
+ public void onRecommendationsChanged() {
+ Handler handler = mWeakHandler.get();
+ PrintServiceRecommendationsChangeListener listener = mWeakListener.get();
+ if (handler != null && listener != null) {
+ handler.obtainMessage(MSG_NOTIFY_PRINT_SERVICE_RECOMMENDATIONS_CHANGED,
+ this).sendToTarget();
+ }
+ }
+
+ public void destroy() {
+ mWeakListener.clear();
+ }
+
+ public PrintServiceRecommendationsChangeListener getListener() {
+ return mWeakListener.get();
+ }
+ }
}
diff --git a/core/java/android/print/PrintServiceRecommendationsLoader.java b/core/java/android/print/PrintServiceRecommendationsLoader.java
new file mode 100644
index 0000000..bb5d065
--- /dev/null
+++ b/core/java/android/print/PrintServiceRecommendationsLoader.java
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.print;
+
+import android.annotation.NonNull;
+import android.content.Context;
+import android.content.Loader;
+import android.os.Handler;
+import android.os.Message;
+import android.printservice.recommendation.RecommendationInfo;
+import com.android.internal.util.Preconditions;
+
+import java.util.List;
+
+/**
+ * Loader for the list of print service recommendations.
+ *
+ * @hide
+ */
+public class PrintServiceRecommendationsLoader extends Loader<List<RecommendationInfo>> {
+ /** The print manager to be used by this object */
+ private final @NonNull PrintManager mPrintManager;
+
+ /** Handler to sequentialize the delivery of the results to the main thread */
+ private final Handler mHandler;
+
+ /** Listens for updates to the data from the platform */
+ private PrintManager.PrintServiceRecommendationsChangeListener mListener;
+
+ /**
+ * Create a new PrintServicesLoader.
+ *
+ * @param printManager The print manager supplying the data
+ * @param context Context of the using object
+ */
+ public PrintServiceRecommendationsLoader(@NonNull PrintManager printManager,
+ @NonNull Context context) {
+ super(Preconditions.checkNotNull(context));
+ mHandler = new MyHandler();
+ mPrintManager = Preconditions.checkNotNull(printManager);
+ }
+
+ @Override
+ protected void onForceLoad() {
+ queueNewResult();
+ }
+
+ /**
+ * Read the print service recommendations and queue it to be delivered on the main thread.
+ */
+ private void queueNewResult() {
+ Message m = mHandler.obtainMessage(0);
+ m.obj = mPrintManager.getPrintServiceRecommendations();
+ mHandler.sendMessage(m);
+ }
+
+ @Override
+ protected void onStartLoading() {
+ mListener = new PrintManager.PrintServiceRecommendationsChangeListener() {
+ @Override
+ public void onPrintServiceRecommendationsChanged() {
+ queueNewResult();
+ }
+ };
+
+ mPrintManager.addPrintServiceRecommendationsChangeListener(mListener);
+
+ // Immediately deliver a result
+ deliverResult(mPrintManager.getPrintServiceRecommendations());
+ }
+
+ @Override
+ protected void onStopLoading() {
+ if (mListener != null) {
+ mPrintManager.removePrintServiceRecommendationsChangeListener(mListener);
+ mListener = null;
+ }
+
+ if (mHandler != null) {
+ mHandler.removeMessages(0);
+ }
+ }
+
+ @Override
+ protected void onReset() {
+ onStopLoading();
+ }
+
+ /**
+ * Handler to sequentialize all the updates to the main thread.
+ */
+ private class MyHandler extends Handler {
+ /**
+ * Create a new handler on the main thread.
+ */
+ public MyHandler() {
+ super(getContext().getMainLooper());
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ if (isStarted()) {
+ deliverResult((List<RecommendationInfo>) msg.obj);
+ }
+ }
+ }
+}
diff --git a/core/java/android/print/PrintServicesLoader.java b/core/java/android/print/PrintServicesLoader.java
index ed41114..60d7d66 100644
--- a/core/java/android/print/PrintServicesLoader.java
+++ b/core/java/android/print/PrintServicesLoader.java
@@ -22,6 +22,7 @@
import android.os.Handler;
import android.os.Message;
import android.printservice.PrintServiceInfo;
+import com.android.internal.util.Preconditions;
import java.util.List;
@@ -46,13 +47,16 @@
/**
* Create a new PrintServicesLoader.
*
+ * @param printManager The print manager supplying the data
+ * @param context Context of the using object
* @param selectionFlags What type of services to load.
*/
public PrintServicesLoader(@NonNull PrintManager printManager, @NonNull Context context,
int selectionFlags) {
- super(context);
- mPrintManager = printManager;
- mSelectionFlags = selectionFlags;
+ super(Preconditions.checkNotNull(context));
+ mPrintManager = Preconditions.checkNotNull(printManager);
+ mSelectionFlags = Preconditions.checkFlagsArgument(selectionFlags,
+ PrintManager.ALL_SERVICES);
}
@Override
diff --git a/core/java/android/print/PrinterCapabilitiesInfo.java b/core/java/android/print/PrinterCapabilitiesInfo.java
index d13879b..01c23f6 100644
--- a/core/java/android/print/PrinterCapabilitiesInfo.java
+++ b/core/java/android/print/PrinterCapabilitiesInfo.java
@@ -24,11 +24,13 @@
import android.print.PrintAttributes.Margins;
import android.print.PrintAttributes.MediaSize;
import android.print.PrintAttributes.Resolution;
+import com.android.internal.util.Preconditions;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
+import java.util.function.IntConsumer;
/**
* This class represents the capabilities of a printer. Instances
@@ -55,9 +57,9 @@
private static final Margins DEFAULT_MARGINS = new Margins(0, 0, 0, 0);
- private Margins mMinMargins = DEFAULT_MARGINS;
- private List<MediaSize> mMediaSizes;
- private List<Resolution> mResolutions;
+ private @NonNull Margins mMinMargins = DEFAULT_MARGINS;
+ private @NonNull List<MediaSize> mMediaSizes;
+ private @NonNull List<Resolution> mResolutions;
private int mColorModes;
private int mDuplexModes;
@@ -205,15 +207,37 @@
return builder.build();
}
+ /**
+ * Call enforceSingle for each bit in the mask.
+ *
+ * @param mask The mask
+ * @param enforceSingle The function to call
+ */
+ private static void enforceValidMask(int mask, IntConsumer enforceSingle) {
+ int current = mask;
+ while (current > 0) {
+ final int currentMode = (1 << Integer.numberOfTrailingZeros(current));
+ current &= ~currentMode;
+ enforceSingle.accept(currentMode);
+ }
+ }
+
private PrinterCapabilitiesInfo(Parcel parcel) {
- mMinMargins = readMargins(parcel);
+ mMinMargins = Preconditions.checkNotNull(readMargins(parcel));
readMediaSizes(parcel);
readResolutions(parcel);
mColorModes = parcel.readInt();
+ enforceValidMask(mColorModes,
+ (currentMode) -> PrintAttributes.enforceValidColorMode(currentMode));
+
mDuplexModes = parcel.readInt();
+ enforceValidMask(mDuplexModes,
+ (currentMode) -> PrintAttributes.enforceValidDuplexMode(currentMode));
readDefaults(parcel);
+ Preconditions.checkArgument(mMediaSizes.size() > mDefaults[PROPERTY_MEDIA_SIZE]);
+ Preconditions.checkArgument(mResolutions.size() > mDefaults[PROPERTY_RESOLUTION]);
}
@Override
@@ -537,12 +561,8 @@
*/
public @NonNull Builder setColorModes(@ColorMode int colorModes,
@ColorMode int defaultColorMode) {
- int currentModes = colorModes;
- while (currentModes > 0) {
- final int currentMode = (1 << Integer.numberOfTrailingZeros(currentModes));
- currentModes &= ~currentMode;
- PrintAttributes.enforceValidColorMode(currentMode);
- }
+ enforceValidMask(colorModes,
+ (currentMode) -> PrintAttributes.enforceValidColorMode(currentMode));
PrintAttributes.enforceValidColorMode(defaultColorMode);
mPrototype.mColorModes = colorModes;
mPrototype.mDefaults[PROPERTY_COLOR_MODE] = defaultColorMode;
@@ -568,12 +588,8 @@
*/
public @NonNull Builder setDuplexModes(@DuplexMode int duplexModes,
@DuplexMode int defaultDuplexMode) {
- int currentModes = duplexModes;
- while (currentModes > 0) {
- final int currentMode = (1 << Integer.numberOfTrailingZeros(currentModes));
- currentModes &= ~currentMode;
- PrintAttributes.enforceValidDuplexMode(currentMode);
- }
+ enforceValidMask(duplexModes,
+ (currentMode) -> PrintAttributes.enforceValidDuplexMode(currentMode));
PrintAttributes.enforceValidDuplexMode(defaultDuplexMode);
mPrototype.mDuplexModes = duplexModes;
mPrototype.mDefaults[PROPERTY_DUPLEX_MODE] = defaultDuplexMode;
diff --git a/core/java/android/printservice/PrinterDiscoverySession.java b/core/java/android/printservice/PrinterDiscoverySession.java
index cd5a903..7b9533d 100644
--- a/core/java/android/printservice/PrinterDiscoverySession.java
+++ b/core/java/android/printservice/PrinterDiscoverySession.java
@@ -18,6 +18,7 @@
import android.annotation.NonNull;
import android.content.pm.ParceledListSlice;
+import android.os.CancellationSignal;
import android.os.RemoteException;
import android.print.PrinterCapabilitiesInfo;
import android.print.PrinterId;
@@ -412,11 +413,13 @@
* service.
*
* @param printerId The printer to icon belongs to.
+ * @param cancellationSignal Signal used to cancel the request
* @param callback Callback for returning the icon to the print spooler.
*
* @see android.print.PrinterInfo.Builder#setHasCustomPrinterIcon()
*/
public void onRequestCustomPrinterIcon(@NonNull PrinterId printerId,
+ @NonNull CancellationSignal cancellationSignal,
@NonNull CustomPrinterIconCallback callback) {
}
@@ -533,7 +536,7 @@
if (!mIsDestroyed && mObserver != null) {
CustomPrinterIconCallback callback = new CustomPrinterIconCallback(printerId,
mObserver);
- onRequestCustomPrinterIcon(printerId, callback);
+ onRequestCustomPrinterIcon(printerId, new CancellationSignal(), callback);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/ui/ResetBackgroundScrimEvent.java b/core/java/android/printservice/recommendation/IRecommendationService.aidl
similarity index 60%
copy from packages/SystemUI/src/com/android/systemui/recents/events/ui/ResetBackgroundScrimEvent.java
copy to core/java/android/printservice/recommendation/IRecommendationService.aidl
index 863f40b..ce9ea6f 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/events/ui/ResetBackgroundScrimEvent.java
+++ b/core/java/android/printservice/recommendation/IRecommendationService.aidl
@@ -14,13 +14,17 @@
* limitations under the License.
*/
-package com.android.systemui.recents.events.ui;
+package android.printservice.recommendation;
-import com.android.systemui.recents.events.EventBus;
+import android.printservice.recommendation.IRecommendationServiceCallbacks;
/**
- * This is sent to reset the background scrim back to the initial state.
+ * Interface for communication with the print service recommendation service.
+ *
+ * @see android.print.IPrintServiceRecommendationServiceCallbacks
+ *
+ * @hide
*/
-public class ResetBackgroundScrimEvent extends EventBus.Event {
- // Simple event
+oneway interface IRecommendationService {
+ void registerCallbacks(in IRecommendationServiceCallbacks callbacks);
}
diff --git a/core/java/android/printservice/recommendation/IRecommendationServiceCallbacks.aidl b/core/java/android/printservice/recommendation/IRecommendationServiceCallbacks.aidl
new file mode 100644
index 0000000..9528654
--- /dev/null
+++ b/core/java/android/printservice/recommendation/IRecommendationServiceCallbacks.aidl
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.printservice.recommendation;
+
+import android.printservice.recommendation.RecommendationInfo;
+
+/**
+ * Callbacks for communication with the print service recommendation service.
+ *
+ * @see android.print.IPrintServiceRecommendationService
+ *
+ * @hide
+ */
+oneway interface IRecommendationServiceCallbacks {
+ /**
+ * Update the print service recommendations.
+ *
+ * @param recommendations the new print service recommendations
+ */
+ void onRecommendationsUpdated(in List<RecommendationInfo> recommendations);
+}
diff --git a/core/java/android/net/IConnectivityMetricsLoggerSubscriber.aidl b/core/java/android/printservice/recommendation/IRecommendationsChangeListener.aidl
similarity index 72%
rename from core/java/android/net/IConnectivityMetricsLoggerSubscriber.aidl
rename to core/java/android/printservice/recommendation/IRecommendationsChangeListener.aidl
index a2c62cd..8ca5c69 100644
--- a/core/java/android/net/IConnectivityMetricsLoggerSubscriber.aidl
+++ b/core/java/android/printservice/recommendation/IRecommendationsChangeListener.aidl
@@ -14,12 +14,13 @@
* limitations under the License.
*/
-package android.net;
+package android.printservice.recommendation;
-import android.net.ConnectivityMetricsEvent;
-
-/** {@hide} */
-oneway interface IConnectivityMetricsLoggerSubscriber {
-
- void onEvents(in ConnectivityMetricsEvent[] events);
+/**
+ * Interface for observing changes of the print service recommendations.
+ *
+ * @hide
+ */
+oneway interface IRecommendationsChangeListener {
+ void onRecommendationsChanged();
}
diff --git a/core/java/android/net/IConnectivityMetricsLoggerSubscriber.aidl b/core/java/android/printservice/recommendation/RecommendationInfo.aidl
similarity index 62%
copy from core/java/android/net/IConnectivityMetricsLoggerSubscriber.aidl
copy to core/java/android/printservice/recommendation/RecommendationInfo.aidl
index a2c62cd..f21d0bf 100644
--- a/core/java/android/net/IConnectivityMetricsLoggerSubscriber.aidl
+++ b/core/java/android/printservice/recommendation/RecommendationInfo.aidl
@@ -1,11 +1,11 @@
-/*
- * Copyright (C) 2016 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.
* You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * 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,
@@ -14,12 +14,9 @@
* limitations under the License.
*/
-package android.net;
+package android.printservice.recommendation;
-import android.net.ConnectivityMetricsEvent;
-
-/** {@hide} */
-oneway interface IConnectivityMetricsLoggerSubscriber {
-
- void onEvents(in ConnectivityMetricsEvent[] events);
-}
+/**
+ * @hide
+ */
+parcelable RecommendationInfo;
diff --git a/core/java/android/printservice/recommendation/RecommendationInfo.java b/core/java/android/printservice/recommendation/RecommendationInfo.java
new file mode 100644
index 0000000..65d534e
--- /dev/null
+++ b/core/java/android/printservice/recommendation/RecommendationInfo.java
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.printservice.recommendation;
+
+import android.annotation.IntRange;
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.printservice.PrintService;
+import com.android.internal.util.Preconditions;
+
+/**
+ * A recommendation to install a {@link PrintService print service}.
+ *
+ * @hide
+ */
+@SystemApi
+public final class RecommendationInfo implements Parcelable {
+ /** Package name of the print service. */
+ private @NonNull final CharSequence mPackageName;
+
+ /** Display name of the print service. */
+ private @NonNull final CharSequence mName;
+
+ /** Number of printers the print service would discover if installed. */
+ private @IntRange(from = 0) final int mNumDiscoveredPrinters;
+
+ /** If the service detects printer from multiple vendors. */
+ private final boolean mRecommendsMultiVendorService;
+
+ /**
+ * Create a new recommendation.
+ *
+ * @param packageName Package name of the print service
+ * @param name Display name of the print service
+ * @param numDiscoveredPrinters Number of printers the print service would discover if
+ * installed
+ * @param recommendsMultiVendorService If the service detects printer from multiple vendor
+ */
+ public RecommendationInfo(@NonNull CharSequence packageName, @NonNull CharSequence name,
+ @IntRange(from = 0) int numDiscoveredPrinters, boolean recommendsMultiVendorService) {
+ mPackageName = Preconditions.checkStringNotEmpty(packageName);
+ mName = Preconditions.checkStringNotEmpty(name);
+ mNumDiscoveredPrinters = Preconditions.checkArgumentNonnegative(numDiscoveredPrinters);
+ mRecommendsMultiVendorService = recommendsMultiVendorService;
+ }
+
+ /**
+ * Create a new recommendation from a parcel.
+ *
+ * @param parcel The parcel containing the data
+ *
+ * @see #CREATOR
+ */
+ private RecommendationInfo(@NonNull Parcel parcel) {
+ this(parcel.readCharSequence(), parcel.readCharSequence(), parcel.readInt(),
+ parcel.readByte() != 0);
+ }
+
+ /**
+ * @return The package name the recommendations recommends.
+ */
+ public CharSequence getPackageName() {
+ return mPackageName;
+ }
+
+ /**
+ * @return Whether the recommended print service detects printers of more than one vendor.
+ */
+ public boolean recommendsMultiVendorService() {
+ return mRecommendsMultiVendorService;
+ }
+
+ /**
+ * @return The number of printer the print service would detect.
+ */
+ public int getNumDiscoveredPrinters() {
+ return mNumDiscoveredPrinters;
+ }
+
+ /**
+ * @return The name of the recommended print service.
+ */
+ public CharSequence getName() {
+ return mName;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeCharSequence(mPackageName);
+ dest.writeCharSequence(mName);
+ dest.writeInt(mNumDiscoveredPrinters);
+ dest.writeByte((byte) (mRecommendsMultiVendorService ? 1 : 0));
+ }
+
+ /**
+ * Utility class used to create new print service recommendation objects from parcels.
+ *
+ * @see #RecommendationInfo(Parcel)
+ */
+ public static final Creator<RecommendationInfo> CREATOR =
+ new Creator<RecommendationInfo>() {
+ @Override
+ public RecommendationInfo createFromParcel(Parcel in) {
+ return new RecommendationInfo(in);
+ }
+
+ @Override
+ public RecommendationInfo[] newArray(int size) {
+ return new RecommendationInfo[size];
+ }
+ };
+}
diff --git a/core/java/android/printservice/recommendation/RecommendationService.java b/core/java/android/printservice/recommendation/RecommendationService.java
new file mode 100644
index 0000000..b7ea512
--- /dev/null
+++ b/core/java/android/printservice/recommendation/RecommendationService.java
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.printservice.recommendation;
+
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.app.Service;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.Message;
+import android.os.RemoteException;
+import android.util.Log;
+import com.android.internal.annotations.GuardedBy;
+
+import java.util.List;
+
+/**
+ * Base class for the print service recommendation services.
+ *
+ * @hide
+ */
+@SystemApi
+public abstract class RecommendationService extends Service {
+ private static final String LOG_TAG = "PrintServiceRecS";
+
+ /** Used to push onConnect and onDisconnect on the main thread */
+ private Handler mHandler;
+
+ /**
+ * The {@link Intent} action that must be declared as handled by a service in its manifest for
+ * the system to recognize it as a print service recommendation service.
+ *
+ * @hide
+ */
+ public static final String SERVICE_INTERFACE =
+ "android.printservice.recommendation.RecommendationService";
+
+ /** Registered callbacks, only modified on main thread */
+ private IRecommendationServiceCallbacks mCallbacks;
+
+ @Override
+ protected void attachBaseContext(Context base) {
+ super.attachBaseContext(base);
+
+ mHandler = new MyHandler();
+ }
+
+ /**
+ * Update the print service recommendations.
+ *
+ * @param recommendations The new set of recommendations
+ */
+ public final void updateRecommendations(@Nullable List<RecommendationInfo> recommendations) {
+ mHandler.obtainMessage(MyHandler.MSG_UPDATE, recommendations).sendToTarget();
+ }
+
+ @Override
+ public final IBinder onBind(Intent intent) {
+ return new IRecommendationService.Stub() {
+ @Override
+ public void registerCallbacks(IRecommendationServiceCallbacks callbacks) {
+ // The callbacks come in order of the caller on oneway calls. Hence while the caller
+ // cannot know at what time the connection is made, he can know the ordering of
+ // connection and disconnection.
+ //
+ // Similar he cannot know when the disconnection is processed, hence he has to
+ // handle callbacks after calling disconnect.
+ if (callbacks != null) {
+ mHandler.obtainMessage(MyHandler.MSG_CONNECT, callbacks).sendToTarget();
+ } else {
+ mHandler.obtainMessage(MyHandler.MSG_DISCONNECT).sendToTarget();
+ }
+ }
+ };
+ }
+
+ /**
+ * Called when the client connects to the recommendation service.
+ */
+ public abstract void onConnected();
+
+ /**
+ * Called when the client disconnects from the recommendation service.
+ */
+ public abstract void onDisconnected();
+
+ private class MyHandler extends Handler {
+ static final int MSG_CONNECT = 1;
+ static final int MSG_DISCONNECT = 2;
+ static final int MSG_UPDATE = 3;
+
+ MyHandler() {
+ super(Looper.getMainLooper());
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case MSG_CONNECT:
+ mCallbacks = (IRecommendationServiceCallbacks) msg.obj;
+ onConnected();
+ break;
+ case MSG_DISCONNECT:
+ onDisconnected();
+ mCallbacks = null;
+ break;
+ case MSG_UPDATE:
+ // Note that there might be a connection change in progress. In this case the
+ // message is handled as before the change. This is acceptable as the caller of
+ // the connection change has not guarantee when the connection change binder
+ // transaction is actually processed.
+ try {
+ mCallbacks.onRecommendationsUpdated((List<RecommendationInfo>) msg.obj);
+ } catch (RemoteException | NullPointerException e) {
+ Log.e(LOG_TAG, "Could not update recommended services", e);
+ }
+ break;
+ }
+ }
+ }
+}
diff --git a/core/java/android/provider/CallLog.java b/core/java/android/provider/CallLog.java
index e2ae133..8ac185a 100644
--- a/core/java/android/provider/CallLog.java
+++ b/core/java/android/provider/CallLog.java
@@ -440,6 +440,13 @@
public static final String POST_DIAL_DIGITS = "post_dial_digits";
/**
+ * For an incoming call, the secondary line number the call was received via.
+ * When a SIM card has multiple phone numbers associated with it, the via number indicates
+ * which of the numbers associated with the SIM was called.
+ */
+ public static final String VIA_NUMBER = "via_number";
+
+ /**
* Indicates that the entry will be copied from primary user to other users.
* <P>Type: INTEGER</P>
*
@@ -485,10 +492,10 @@
public static Uri addCall(CallerInfo ci, Context context, String number,
int presentation, int callType, int features, PhoneAccountHandle accountHandle,
long start, int duration, Long dataUsage) {
- return addCall(ci, context, number, /* postDialDigits =*/ "", presentation,
- callType, features, accountHandle,
- start, duration, dataUsage, /* addForAllUsers =*/ false,
- /* userToBeInsertedTo =*/ null, /* is_read =*/ false);
+ return addCall(ci, context, number, /* postDialDigits =*/ "", /* viaNumber =*/ "",
+ presentation, callType, features, accountHandle, start, duration,
+ dataUsage, /* addForAllUsers =*/ false, /* userToBeInsertedTo =*/ null,
+ /* is_read =*/ false);
}
@@ -499,6 +506,8 @@
* if the contact is unknown.
* @param context the context used to get the ContentResolver
* @param number the phone number to be added to the calls db
+ * @param viaNumber the secondary number that the incoming call received with. If the
+ * call was received with the SIM assigned number, then this field must be ''.
* @param presentation enum value from PhoneConstants.PRESENTATION_xxx, which
* is set by the network and denotes the number presenting rules for
* "allowed", "payphone", "restricted" or "unknown"
@@ -519,12 +528,12 @@
* {@hide}
*/
public static Uri addCall(CallerInfo ci, Context context, String number,
- String postDialDigits, int presentation, int callType, int features,
- PhoneAccountHandle accountHandle, long start, int duration, Long dataUsage,
- boolean addForAllUsers, UserHandle userToBeInsertedTo) {
- return addCall(ci, context, number, postDialDigits, presentation, callType, features,
- accountHandle, start, duration, dataUsage, addForAllUsers, userToBeInsertedTo,
- /* is_read =*/ false);
+ String postDialDigits, String viaNumber, int presentation, int callType,
+ int features, PhoneAccountHandle accountHandle, long start, int duration,
+ Long dataUsage, boolean addForAllUsers, UserHandle userToBeInsertedTo) {
+ return addCall(ci, context, number, postDialDigits, viaNumber, presentation, callType,
+ features, accountHandle, start, duration, dataUsage, addForAllUsers,
+ userToBeInsertedTo, /* is_read =*/ false);
}
/**
@@ -536,6 +545,8 @@
* @param number the phone number to be added to the calls db
* @param postDialDigits the post-dial digits that were dialed after the number,
* if it was outgoing. Otherwise it is ''.
+ * @param viaNumber the secondary number that the incoming call received with. If the
+ * call was received with the SIM assigned number, then this field must be ''.
* @param presentation enum value from PhoneConstants.PRESENTATION_xxx, which
* is set by the network and denotes the number presenting rules for
* "allowed", "payphone", "restricted" or "unknown"
@@ -560,9 +571,10 @@
* {@hide}
*/
public static Uri addCall(CallerInfo ci, Context context, String number,
- String postDialDigits, int presentation, int callType, int features,
- PhoneAccountHandle accountHandle, long start, int duration, Long dataUsage,
- boolean addForAllUsers, UserHandle userToBeInsertedTo, boolean is_read) {
+ String postDialDigits, String viaNumber, int presentation, int callType,
+ int features, PhoneAccountHandle accountHandle, long start, int duration,
+ Long dataUsage, boolean addForAllUsers, UserHandle userToBeInsertedTo,
+ boolean is_read) {
if (VERBOSE_LOG) {
Log.v(LOG_TAG, String.format("Add call: number=%s, user=%s, for all=%s",
number, userToBeInsertedTo, addForAllUsers));
@@ -618,6 +630,7 @@
values.put(NUMBER, number);
values.put(POST_DIAL_DIGITS, postDialDigits);
+ values.put(VIA_NUMBER, viaNumber);
values.put(NUMBER_PRESENTATION, Integer.valueOf(numberPresentation));
values.put(TYPE, Integer.valueOf(callType));
values.put(FEATURES, features);
diff --git a/core/java/android/provider/DocumentsContract.java b/core/java/android/provider/DocumentsContract.java
index 4412459..aba3972 100644
--- a/core/java/android/provider/DocumentsContract.java
+++ b/core/java/android/provider/DocumentsContract.java
@@ -112,9 +112,8 @@
* thumbnail should be rotated.
*
* @see MediaStore.Images.ImageColumns#ORIENTATION
- * @hide
*/
- public static final String EXTRA_ORIENTATION = "android.content.extra.ORIENTATION";
+ public static final String EXTRA_ORIENTATION = "android.provider.extra.ORIENTATION";
/**
* Overrides the default prompt text in DocumentsUI when set in an intent.
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index f7e0e03..f4d63ac 100755
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -1569,9 +1569,8 @@
* @return true if the calling app can draw on top of other apps, false otherwise.
*/
public static boolean canDrawOverlays(Context context) {
- int uid = Binder.getCallingUid();
- return Settings.isCallingPackageAllowedToDrawOverlays(context, uid, Settings
- .getPackageNameForUid(context, uid), false);
+ return Settings.isCallingPackageAllowedToDrawOverlays(context, Process.myUid(),
+ context.getOpPackageName(), false);
}
/**
@@ -3885,9 +3884,8 @@
* @return true if the calling app can write to system settings, false otherwise
*/
public static boolean canWrite(Context context) {
- int uid = Binder.getCallingUid();
- return isCallingPackageAllowedToWriteSettings(context, uid, getPackageNameForUid(
- context, uid), false);
+ return isCallingPackageAllowedToWriteSettings(context, Process.myUid(),
+ context.getOpPackageName(), false);
}
}
@@ -3991,6 +3989,7 @@
MOVED_TO_GLOBAL.add(Settings.Global.WIFI_SAVED_STATE);
MOVED_TO_GLOBAL.add(Settings.Global.WIFI_SUPPLICANT_SCAN_INTERVAL_MS);
MOVED_TO_GLOBAL.add(Settings.Global.WIFI_SUSPEND_OPTIMIZATIONS_ENABLED);
+ MOVED_TO_GLOBAL.add(Settings.Global.WIFI_VERBOSE_LOGGING_ENABLED);
MOVED_TO_GLOBAL.add(Settings.Global.WIFI_ENHANCED_AUTO_JOIN);
MOVED_TO_GLOBAL.add(Settings.Global.WIFI_NETWORK_SHOW_RSSI);
MOVED_TO_GLOBAL.add(Settings.Global.WIFI_WATCHDOG_ON);
@@ -6089,7 +6088,6 @@
MOUNT_UMS_AUTOSTART,
MOUNT_UMS_PROMPT,
MOUNT_UMS_NOTIFY_ENABLED,
- UI_NIGHT_MODE,
SLEEP_TIMEOUT,
DOUBLE_TAP_TO_WAKE,
WAKE_GESTURE_ENABLED,
@@ -7259,6 +7257,14 @@
"wifi_suspend_optimizations_enabled";
/**
+ * Setting to enable verbose logging in Wi-Fi; disabled by default, and setting to 1
+ * will enable it. In the future, additional values may be supported.
+ * @hide
+ */
+ public static final String WIFI_VERBOSE_LOGGING_ENABLED =
+ "wifi_verbose_logging_enabled";
+
+ /**
* The maximum number of times we will retry a connection to an access
* point for which we have failed in acquiring an IP address from DHCP.
* A value of N means that we will make N+1 connection attempts in all.
@@ -7680,6 +7686,9 @@
BLUETOOTH_MAP_PRIORITY_PREFIX = "bluetooth_map_priority_";
/** {@hide} */
public static final String
+ BLUETOOTH_PBAP_CLIENT_PRIORITY_PREFIX = "bluetooth_pbap_client_priority_";
+ /** {@hide} */
+ public static final String
BLUETOOTH_SAP_PRIORITY_PREFIX = "bluetooth_sap_priority_";
/**
@@ -7835,6 +7844,14 @@
}
/**
+ * Get the key that retrieves a bluetooth pbap client priority.
+ * @hide
+ */
+ public static final String getBluetoothPbapClientPriorityKey(String address) {
+ return BLUETOOTH_PBAP_CLIENT_PRIORITY_PREFIX + address.toUpperCase(Locale.ROOT);
+ }
+
+ /**
* Get the key that retrieves a bluetooth map priority.
* @hide
*/
diff --git a/core/java/android/security/net/config/NetworkSecurityTrustManager.java b/core/java/android/security/net/config/NetworkSecurityTrustManager.java
index f2c718cd..3c292ca 100644
--- a/core/java/android/security/net/config/NetworkSecurityTrustManager.java
+++ b/core/java/android/security/net/config/NetworkSecurityTrustManager.java
@@ -20,6 +20,7 @@
import android.util.ArrayMap;
import java.io.IOException;
+import java.net.Socket;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.security.GeneralSecurityException;
@@ -29,14 +30,15 @@
import java.util.Map;
import java.util.Set;
-import javax.net.ssl.X509TrustManager;
+import javax.net.ssl.SSLEngine;
+import javax.net.ssl.X509ExtendedTrustManager;
/**
- * {@link X509TrustManager} that implements the trust anchor and pinning for a
+ * {@link X509ExtendedTrustManager} that implements the trust anchor and pinning for a
* given {@link NetworkSecurityConfig}.
* @hide
*/
-public class NetworkSecurityTrustManager implements X509TrustManager {
+public class NetworkSecurityTrustManager extends X509ExtendedTrustManager {
// TODO: Replace this with a general X509TrustManager and use duck-typing.
private final TrustManagerImpl mDelegate;
private final NetworkSecurityConfig mNetworkSecurityConfig;
@@ -68,9 +70,37 @@
}
@Override
+ public void checkClientTrusted(X509Certificate[] certs, String authType, Socket socket)
+ throws CertificateException {
+ mDelegate.checkClientTrusted(certs, authType, socket);
+ }
+
+ @Override
+ public void checkClientTrusted(X509Certificate[] certs, String authType, SSLEngine engine)
+ throws CertificateException {
+ mDelegate.checkClientTrusted(certs, authType, engine);
+ }
+
+ @Override
public void checkServerTrusted(X509Certificate[] certs, String authType)
throws CertificateException {
- checkServerTrusted(certs, authType, null);
+ checkServerTrusted(certs, authType, (String) null);
+ }
+
+ @Override
+ public void checkServerTrusted(X509Certificate[] certs, String authType, Socket socket)
+ throws CertificateException {
+ List<X509Certificate> trustedChain =
+ mDelegate.getTrustedChainForServer(certs, authType, socket);
+ checkPins(trustedChain);
+ }
+
+ @Override
+ public void checkServerTrusted(X509Certificate[] certs, String authType, SSLEngine engine)
+ throws CertificateException {
+ List<X509Certificate> trustedChain =
+ mDelegate.getTrustedChainForServer(certs, authType, engine);
+ checkPins(trustedChain);
}
/**
diff --git a/core/java/android/security/net/config/RootTrustManager.java b/core/java/android/security/net/config/RootTrustManager.java
index b4e58e6..19f6887 100644
--- a/core/java/android/security/net/config/RootTrustManager.java
+++ b/core/java/android/security/net/config/RootTrustManager.java
@@ -16,24 +16,28 @@
package android.security.net.config;
+import java.net.Socket;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.List;
-import javax.net.ssl.X509TrustManager;
+import javax.net.ssl.SSLSocket;
+import javax.net.ssl.SSLEngine;
+import javax.net.ssl.SSLSession;
+import javax.net.ssl.X509ExtendedTrustManager;
/**
- * {@link X509TrustManager} based on an {@link ApplicationConfig}.
+ * {@link X509ExtendedTrustManager} based on an {@link ApplicationConfig}.
*
- * <p>This {@code X509TrustManager} delegates to the specific trust manager for the hostname
- * being used for the connection (See {@link ApplicationConfig#getConfigForHostname(String)} and
+ * <p>This trust manager delegates to the specific trust manager for the hostname being used for
+ * the connection (See {@link ApplicationConfig#getConfigForHostname(String)} and
* {@link NetworkSecurityTrustManager}).</p>
*
* Note that if the {@code ApplicationConfig} has per-domain configurations the hostname aware
* {@link #checkServerTrusted(X509Certificate[], String String)} must be used instead of the normal
* non-aware call.
* @hide */
-public class RootTrustManager implements X509TrustManager {
+public class RootTrustManager extends X509ExtendedTrustManager {
private final ApplicationConfig mConfig;
public RootTrustManager(ApplicationConfig config) {
@@ -53,6 +57,54 @@
}
@Override
+ public void checkClientTrusted(X509Certificate[] certs, String authType, Socket socket)
+ throws CertificateException {
+ // Use the default configuration for all client authentication. Domain specific configs are
+ // only for use in checking server trust not client trust.
+ NetworkSecurityConfig config = mConfig.getConfigForHostname("");
+ config.getTrustManager().checkClientTrusted(certs, authType, socket);
+ }
+
+ @Override
+ public void checkClientTrusted(X509Certificate[] certs, String authType, SSLEngine engine)
+ throws CertificateException {
+ // Use the default configuration for all client authentication. Domain specific configs are
+ // only for use in checking server trust not client trust.
+ NetworkSecurityConfig config = mConfig.getConfigForHostname("");
+ config.getTrustManager().checkClientTrusted(certs, authType, engine);
+ }
+
+ @Override
+ public void checkServerTrusted(X509Certificate[] certs, String authType, Socket socket)
+ throws CertificateException {
+ if (socket instanceof SSLSocket) {
+ SSLSocket sslSocket = (SSLSocket) socket;
+ SSLSession session = sslSocket.getHandshakeSession();
+ if (session == null) {
+ throw new CertificateException("Not in handshake; no session available");
+ }
+ String host = session.getPeerHost();
+ NetworkSecurityConfig config = mConfig.getConfigForHostname(host);
+ config.getTrustManager().checkServerTrusted(certs, authType, socket);
+ } else {
+ // Not an SSLSocket, use the hostname unaware checkServerTrusted.
+ checkServerTrusted(certs, authType);
+ }
+ }
+
+ @Override
+ public void checkServerTrusted(X509Certificate[] certs, String authType, SSLEngine engine)
+ throws CertificateException {
+ SSLSession session = engine.getHandshakeSession();
+ if (session == null) {
+ throw new CertificateException("Not in handshake; no session available");
+ }
+ String host = session.getPeerHost();
+ NetworkSecurityConfig config = mConfig.getConfigForHostname(host);
+ config.getTrustManager().checkServerTrusted(certs, authType, engine);
+ }
+
+ @Override
public void checkServerTrusted(X509Certificate[] certs, String authType)
throws CertificateException {
if (mConfig.hasPerDomainConfigs()) {
diff --git a/core/java/android/service/dreams/DreamService.java b/core/java/android/service/dreams/DreamService.java
index 7af0b05..0557d13 100644
--- a/core/java/android/service/dreams/DreamService.java
+++ b/core/java/android/service/dreams/DreamService.java
@@ -35,7 +35,6 @@
import android.view.ActionMode;
import android.view.Display;
import android.view.KeyEvent;
-import android.view.KeyboardShortcutGroup;
import android.view.Menu;
import android.view.MenuItem;
import android.view.MotionEvent;
diff --git a/core/java/android/text/BoringLayout.java b/core/java/android/text/BoringLayout.java
index a1bc2d1..328fe99 100644
--- a/core/java/android/text/BoringLayout.java
+++ b/core/java/android/text/BoringLayout.java
@@ -300,6 +300,8 @@
Metrics fm = metrics;
if (fm == null) {
fm = new Metrics();
+ } else {
+ fm.reset();
}
TextLine line = TextLine.obtain();
@@ -414,8 +416,6 @@
mEllipsizedCount = end - start;
}
- private static final char FIRST_RIGHT_TO_LEFT = '\u0590';
-
private String mDirect;
private Paint mPaint;
@@ -430,5 +430,14 @@
@Override public String toString() {
return super.toString() + " width=" + width;
}
+
+ private void reset() {
+ top = 0;
+ bottom = 0;
+ ascent = 0;
+ descent = 0;
+ width = 0;
+ leading = 0;
+ }
}
}
diff --git a/core/java/android/text/Hyphenator.java b/core/java/android/text/Hyphenator.java
index 085613f..356804e 100644
--- a/core/java/android/text/Hyphenator.java
+++ b/core/java/android/text/Hyphenator.java
@@ -152,6 +152,9 @@
{"en-UM", "en-US"}, // English (United States Minor Outlying Islands)
{"en-VI", "en-US"}, // English (Virgin Islands)
+ // All English locales other than those falling back to en-US are mapped to en-GB.
+ {"en", "en-GB"},
+
// For German, we're assuming the 1996 (and later) orthography by default.
{"de", "de-1996"},
// Liechtenstein uses the Swiss hyphenation rules for the 1901 orthography.
@@ -160,6 +163,9 @@
// Norwegian is very probably Norwegian Bokmål.
{"no", "nb"},
+ // Use mn-Cyrl. According to CLDR's likelySubtags.xml, mn is most likely to be mn-Cyrl.
+ {"mn", "mn-Cyrl"}, // Mongolian
+
// Fall back to Ethiopic script for languages likely to be written in Ethiopic.
// Data is from CLDR's likelySubtags.xml.
// TODO: Convert this to a mechanism using ICU4J's ULocale#addLikelySubtags().
@@ -182,15 +188,36 @@
// TODO: replace this with a discovery-based method that looks into /system/usr/hyphen-data
String[] availableLanguages = {
+ "as",
+ "bn",
+ "cy",
+ "da",
"de-1901", "de-1996", "de-CH-1901",
- "en-US",
+ "en-GB", "en-US",
"es",
+ "et",
+ "eu",
+ "fr",
+ "ga",
+ "gu",
+ "hi",
+ "hr",
"hu",
"hy",
+ "kn",
+ "ml",
+ "mn-Cyrl",
+ "mr",
"nb",
"nn",
+ "or",
+ "pa",
"pt",
- "und-Ethi"
+ "sl",
+ "ta",
+ "te",
+ "tk",
+ "und-Ethi",
};
for (int i = 0; i < availableLanguages.length; i++) {
String languageTag = availableLanguages[i];
diff --git a/core/java/android/transition/Visibility.java b/core/java/android/transition/Visibility.java
index 4eaab37..6579212 100644
--- a/core/java/android/transition/Visibility.java
+++ b/core/java/android/transition/Visibility.java
@@ -84,6 +84,7 @@
}
private int mMode = MODE_IN | MODE_OUT;
+ private boolean mSuppressLayout = true;
public Visibility() {}
@@ -98,6 +99,15 @@
}
/**
+ * This tells the Visibility transition to suppress layout during the transition and release
+ * the suppression after the transition.
+ * @hide
+ */
+ public void setSuppressLayout(boolean suppress) {
+ this.mSuppressLayout = suppress;
+ }
+
+ /**
* Changes the transition to support appearing and/or disappearing Views, depending
* on <code>mode</code>.
*
@@ -428,7 +438,7 @@
Animator animator = onDisappear(sceneRoot, viewToKeep, startValues, endValues);
if (animator != null) {
DisappearListener disappearListener = new DisappearListener(viewToKeep,
- finalVisibility);
+ finalVisibility, mSuppressLayout);
animator.addListener(disappearListener);
animator.addPauseListener(disappearListener);
addListener(disappearListener);
@@ -483,14 +493,16 @@
private final View mView;
private final int mFinalVisibility;
private final ViewGroup mParent;
+ private final boolean mSuppressLayout;
private boolean mLayoutSuppressed;
boolean mCanceled = false;
- public DisappearListener(View view, int finalVisibility) {
+ public DisappearListener(View view, int finalVisibility, boolean suppressLayout) {
this.mView = view;
this.mFinalVisibility = finalVisibility;
this.mParent = (ViewGroup) view.getParent();
+ this.mSuppressLayout = suppressLayout;
// Prevent a layout from including mView in its calculation.
suppressLayout(true);
}
@@ -555,7 +567,7 @@
}
private void suppressLayout(boolean suppress) {
- if (mLayoutSuppressed != suppress && mParent != null) {
+ if (mSuppressLayout && mLayoutSuppressed != suppress && mParent != null) {
mLayoutSuppressed = suppress;
mParent.suppressLayout(suppress);
}
diff --git a/core/java/android/util/Pair.java b/core/java/android/util/Pair.java
index 6027d08..f96da72 100644
--- a/core/java/android/util/Pair.java
+++ b/core/java/android/util/Pair.java
@@ -16,7 +16,7 @@
package android.util;
-import libcore.util.Objects;
+import java.util.Objects;
/**
* Container to ease passing around a tuple of two objects. This object provides a sensible
@@ -52,7 +52,7 @@
return false;
}
Pair<?, ?> p = (Pair<?, ?>) o;
- return Objects.equal(p.first, first) && Objects.equal(p.second, second);
+ return Objects.equals(p.first, first) && Objects.equals(p.second, second);
}
/**
@@ -65,6 +65,11 @@
return (first == null ? 0 : first.hashCode()) ^ (second == null ? 0 : second.hashCode());
}
+ @Override
+ public String toString() {
+ return "Pair{" + String.valueOf(first) + " " + String.valueOf(second) + "}";
+ }
+
/**
* Convenience method for creating an appropriately typed pair.
* @param a the first object in the Pair
diff --git a/core/java/android/util/apk/ApkSignatureSchemeV2Verifier.java b/core/java/android/util/apk/ApkSignatureSchemeV2Verifier.java
index d9227ce..78d3b7b 100644
--- a/core/java/android/util/apk/ApkSignatureSchemeV2Verifier.java
+++ b/core/java/android/util/apk/ApkSignatureSchemeV2Verifier.java
@@ -606,7 +606,6 @@
private static final int SIGNATURE_ECDSA_WITH_SHA256 = 0x0201;
private static final int SIGNATURE_ECDSA_WITH_SHA512 = 0x0202;
private static final int SIGNATURE_DSA_WITH_SHA256 = 0x0301;
- private static final int SIGNATURE_DSA_WITH_SHA512 = 0x0302;
private static final int CONTENT_DIGEST_CHUNKED_SHA256 = 1;
private static final int CONTENT_DIGEST_CHUNKED_SHA512 = 2;
@@ -620,7 +619,6 @@
case SIGNATURE_ECDSA_WITH_SHA256:
case SIGNATURE_ECDSA_WITH_SHA512:
case SIGNATURE_DSA_WITH_SHA256:
- case SIGNATURE_DSA_WITH_SHA512:
return true;
default:
return false;
@@ -670,7 +668,6 @@
case SIGNATURE_RSA_PSS_WITH_SHA512:
case SIGNATURE_RSA_PKCS1_V1_5_WITH_SHA512:
case SIGNATURE_ECDSA_WITH_SHA512:
- case SIGNATURE_DSA_WITH_SHA512:
return CONTENT_DIGEST_CHUNKED_SHA512;
default:
throw new IllegalArgumentException(
@@ -714,7 +711,6 @@
case SIGNATURE_ECDSA_WITH_SHA512:
return "EC";
case SIGNATURE_DSA_WITH_SHA256:
- case SIGNATURE_DSA_WITH_SHA512:
return "DSA";
default:
throw new IllegalArgumentException(
@@ -746,8 +742,6 @@
return Pair.create("SHA512withECDSA", null);
case SIGNATURE_DSA_WITH_SHA256:
return Pair.create("SHA256withDSA", null);
- case SIGNATURE_DSA_WITH_SHA512:
- return Pair.create("SHA512withDSA", null);
default:
throw new IllegalArgumentException(
"Unknown signature algorithm: 0x"
diff --git a/core/java/android/view/ContextThemeWrapper.java b/core/java/android/view/ContextThemeWrapper.java
index 4888877..86318e9 100644
--- a/core/java/android/view/ContextThemeWrapper.java
+++ b/core/java/android/view/ContextThemeWrapper.java
@@ -101,6 +101,15 @@
mOverrideConfiguration = new Configuration(overrideConfiguration);
}
+ /**
+ * Used by ActivityThread to apply the overridden configuration to onConfigurationChange
+ * callbacks.
+ * @hide
+ */
+ public Configuration getOverrideConfiguration() {
+ return mOverrideConfiguration;
+ }
+
@Override
public AssetManager getAssets() {
// Ensure we're returning assets with the correct configuration.
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index 7af4a1f..4ba97d5 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -180,7 +180,12 @@
// caller must call setNewConfiguration() sometime later.
Configuration updateOrientationFromAppTokens(in Configuration currentConfig,
IBinder freezeThisOneIfNeeded);
- void setNewConfiguration(in Configuration config);
+ // Notify window manager of the new configuration. Returns an array of stack ids that's
+ // affected by the update, ActivityManager should resize these stacks.
+ int[] setNewConfiguration(in Configuration config);
+
+ // Retrieves the new bounds after the configuration update evaluated by window manager.
+ Rect getBoundsForNewConfiguration(int stackId);
void startFreezingScreen(int exitAnim, int enterAnim);
void stopFreezingScreen();
@@ -400,4 +405,14 @@
* @hide
*/
void registerShortcutKey(in long shortcutCode, IShortcutService keySubscriber);
+
+ /**
+ * Create the input consumer for wallpaper events.
+ */
+ void createWallpaperInputConsumer(out InputChannel inputChannel);
+
+ /**
+ * Remove the input consumer for wallpaper events.
+ */
+ void removeWallpaperInputConsumer();
}
diff --git a/core/java/android/view/IWindowSession.aidl b/core/java/android/view/IWindowSession.aidl
index a1e2e94..8e1609c 100644
--- a/core/java/android/view/IWindowSession.aidl
+++ b/core/java/android/view/IWindowSession.aidl
@@ -116,14 +116,11 @@
* @param top The new top position
* @param right The new right position
* @param bottom The new bottom position
- * @param requestedWidth The new requested width
- * @param requestedHeight The new requested height
* @param deferTransactionUntilFrame Frame number from our parent (attached) to
* defer this action until.
* @param outFrame Rect in which is placed the new position/size on screen.
*/
void repositionChild(IWindow childWindow, int left, int top, int right, int bottom,
- int requestedWidth, int requestedHeight,
long deferTransactionUntilFrame, out Rect outFrame);
/*
diff --git a/core/java/android/view/KeyboardShortcutInfo.java b/core/java/android/view/KeyboardShortcutInfo.java
index c2bd347..eee925d 100644
--- a/core/java/android/view/KeyboardShortcutInfo.java
+++ b/core/java/android/view/KeyboardShortcutInfo.java
@@ -51,7 +51,7 @@
mLabel = label;
mIcon = icon;
mBaseCharacter = MIN_VALUE;
- checkArgument(keycode > KeyEvent.KEYCODE_UNKNOWN && keycode <= KeyEvent.getMaxKeyCode());
+ checkArgument(keycode >= KeyEvent.KEYCODE_UNKNOWN && keycode <= KeyEvent.getMaxKeyCode());
mKeycode = keycode;
mModifiers = modifiers;
}
diff --git a/core/java/android/view/RenderNode.java b/core/java/android/view/RenderNode.java
index a19254f..ab4cbcf 100644
--- a/core/java/android/view/RenderNode.java
+++ b/core/java/android/view/RenderNode.java
@@ -307,18 +307,22 @@
*
* Deep copies the data into native to simplify reference ownership.
*/
- public boolean setOutline(Outline outline) {
+ public boolean setOutline(@Nullable Outline outline) {
if (outline == null) {
return nSetOutlineNone(mNativeRenderNode);
- } else if (outline.isEmpty()) {
- return nSetOutlineEmpty(mNativeRenderNode);
- } else if (outline.mRect != null) {
- return nSetOutlineRoundRect(mNativeRenderNode, outline.mRect.left, outline.mRect.top,
- outline.mRect.right, outline.mRect.bottom, outline.mRadius, outline.mAlpha);
- } else if (outline.mPath != null) {
- return nSetOutlineConvexPath(mNativeRenderNode, outline.mPath.mNativePath,
- outline.mAlpha);
}
+
+ switch(outline.mMode) {
+ case Outline.MODE_EMPTY:
+ return nSetOutlineEmpty(mNativeRenderNode);
+ case Outline.MODE_ROUND_RECT:
+ return nSetOutlineRoundRect(mNativeRenderNode, outline.mRect.left, outline.mRect.top,
+ outline.mRect.right, outline.mRect.bottom, outline.mRadius, outline.mAlpha);
+ case Outline.MODE_CONVEX_PATH:
+ return nSetOutlineConvexPath(mNativeRenderNode, outline.mPath.mNativePath,
+ outline.mAlpha);
+ }
+
throw new IllegalArgumentException("Unrecognized outline?");
}
@@ -763,6 +767,16 @@
return nGetDebugSize(mNativeRenderNode);
}
+ /**
+ * Called by native when the passed displaylist is removed from the draw tree
+ */
+ void onRenderNodeDetached() {
+ discardDisplayList();
+ if (mOwningView != null) {
+ mOwningView.onRenderNodeDetached(this);
+ }
+ }
+
///////////////////////////////////////////////////////////////////////////
// Animations
///////////////////////////////////////////////////////////////////////////
@@ -795,7 +809,9 @@
// Native methods
///////////////////////////////////////////////////////////////////////////
- private static native long nCreate(String name);
+ // Intentionally not static because it acquires a reference to 'this'
+ private native long nCreate(String name);
+
private static native void nDestroyRenderNode(long renderNode);
private static native void nSetDisplayList(long renderNode, long newData);
diff --git a/core/java/android/view/ScaleGestureDetector.java b/core/java/android/view/ScaleGestureDetector.java
index 37e4000..7cd161c 100644
--- a/core/java/android/view/ScaleGestureDetector.java
+++ b/core/java/android/view/ScaleGestureDetector.java
@@ -145,13 +145,6 @@
private int mSpanSlop;
private int mMinSpan;
- // Bounds for recently seen values
- private float mTouchUpper;
- private float mTouchLower;
- private float mTouchHistoryLastAccepted;
- private int mTouchHistoryDirection;
- private long mTouchHistoryLastAcceptedTime;
- private int mTouchMinMajor;
private final Handler mHandler;
private float mAnchoredScaleStartX;
@@ -207,8 +200,6 @@
mSpanSlop = ViewConfiguration.get(context).getScaledTouchSlop() * 2;
final Resources res = context.getResources();
- mTouchMinMajor = res.getDimensionPixelSize(
- com.android.internal.R.dimen.config_minScalingTouchMajor);
mMinSpan = res.getDimensionPixelSize(com.android.internal.R.dimen.config_minScalingSpan);
mHandler = handler;
// Quick scale is enabled by default after JB_MR2
@@ -223,77 +214,6 @@
}
/**
- * The touchMajor/touchMinor elements of a MotionEvent can flutter/jitter on
- * some hardware/driver combos. Smooth it out to get kinder, gentler behavior.
- * @param ev MotionEvent to add to the ongoing history
- */
- private void addTouchHistory(MotionEvent ev) {
- final long currentTime = SystemClock.uptimeMillis();
- final int count = ev.getPointerCount();
- boolean accept = currentTime - mTouchHistoryLastAcceptedTime >= TOUCH_STABILIZE_TIME;
- float total = 0;
- int sampleCount = 0;
- for (int i = 0; i < count; i++) {
- final boolean hasLastAccepted = !Float.isNaN(mTouchHistoryLastAccepted);
- final int historySize = ev.getHistorySize();
- final int pointerSampleCount = historySize + 1;
- for (int h = 0; h < pointerSampleCount; h++) {
- float major;
- if (h < historySize) {
- major = ev.getHistoricalTouchMajor(i, h);
- } else {
- major = ev.getTouchMajor(i);
- }
- if (major < mTouchMinMajor) major = mTouchMinMajor;
- total += major;
-
- if (Float.isNaN(mTouchUpper) || major > mTouchUpper) {
- mTouchUpper = major;
- }
- if (Float.isNaN(mTouchLower) || major < mTouchLower) {
- mTouchLower = major;
- }
-
- if (hasLastAccepted) {
- final int directionSig = (int) Math.signum(major - mTouchHistoryLastAccepted);
- if (directionSig != mTouchHistoryDirection ||
- (directionSig == 0 && mTouchHistoryDirection == 0)) {
- mTouchHistoryDirection = directionSig;
- final long time = h < historySize ? ev.getHistoricalEventTime(h)
- : ev.getEventTime();
- mTouchHistoryLastAcceptedTime = time;
- accept = false;
- }
- }
- }
- sampleCount += pointerSampleCount;
- }
-
- final float avg = total / sampleCount;
-
- if (accept) {
- float newAccepted = (mTouchUpper + mTouchLower + avg) / 3;
- mTouchUpper = (mTouchUpper + newAccepted) / 2;
- mTouchLower = (mTouchLower + newAccepted) / 2;
- mTouchHistoryLastAccepted = newAccepted;
- mTouchHistoryDirection = 0;
- mTouchHistoryLastAcceptedTime = ev.getEventTime();
- }
- }
-
- /**
- * Clear all touch history tracking. Useful in ACTION_CANCEL or ACTION_UP.
- * @see #addTouchHistory(MotionEvent)
- */
- private void clearTouchHistory() {
- mTouchUpper = Float.NaN;
- mTouchLower = Float.NaN;
- mTouchHistoryLastAccepted = Float.NaN;
- mTouchHistoryDirection = 0;
- mTouchHistoryLastAcceptedTime = 0;
- }
-
- /**
* Accepts MotionEvents and dispatches events to a {@link OnScaleGestureListener}
* when appropriate.
*
@@ -344,7 +264,6 @@
}
if (streamComplete) {
- clearTouchHistory();
return true;
}
}
@@ -391,17 +310,14 @@
focusY = sumY / div;
}
- addTouchHistory(event);
-
// Determine average deviation from focal point
float devSumX = 0, devSumY = 0;
for (int i = 0; i < count; i++) {
if (skipIndex == i) continue;
// Convert the resulting diameter into a radius.
- final float touchSize = mTouchHistoryLastAccepted / 2;
- devSumX += Math.abs(event.getX(i) - focusX) + touchSize;
- devSumY += Math.abs(event.getY(i) - focusY) + touchSize;
+ devSumX += Math.abs(event.getX(i) - focusX);
+ devSumY += Math.abs(event.getY(i) - focusY);
}
final float devX = devSumX / div;
final float devY = devSumY / div;
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index 477ffd9..8a8fb43 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -490,7 +490,7 @@
| WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
| WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
;
- if (!creating && !force && !mUpdateWindowNeeded) {
+ if (!creating && !force && !mUpdateWindowNeeded && !sizeChanged) {
mLayout.privateFlags |=
WindowManager.LayoutParams.PRIVATE_FLAG_PRESERVE_GEOMETRY;
} else {
@@ -584,18 +584,6 @@
mSurface.transferFrom(mNewSurface);
if (visible && mSurface.isValid()) {
- // We set SCALING_MODE_NO_SCALE_CROP to allow the WindowManager
- // to update our Surface crop without requiring a new buffer from
- // us. In the default mode of SCALING_MODE_FREEZE, surface geometry
- // state (which includes crop) is only applied when a buffer
- // with appropriate geometry is available. During drag resize
- // it is quite frequent that a matching buffer will not be available
- // (because we are constantly being resized and have fallen behind).
- // However in such situations the WindowManager still needs to be able
- // to update our crop to ensure we stay within the bounds of the containing
- // window.
- mSurface.setScalingMode(Surface.SCALING_MODE_NO_SCALE_CROP);
-
if (!mSurfaceCreated && (surfaceChanged || visibleChanged)) {
mSurfaceCreated = true;
mIsCreating = true;
@@ -666,7 +654,6 @@
mLocation[0], mLocation[1]));
mSession.repositionChild(mWindow, mWindowSpaceLeft, mWindowSpaceTop,
mLocation[0], mLocation[1],
- mWindowSpaceWidth, mWindowSpaceHeight,
-1, mWinFrame);
} catch (RemoteException ex) {
Log.e(TAG, "Exception from relayout", ex);
@@ -703,7 +690,6 @@
}
// Just using mRTLastReportedPosition as a dummy rect here
session.repositionChild(window, left, top, right, bottom,
- mWindowSpaceWidth, mWindowSpaceHeight,
frameNumber,
mRTLastReportedPosition);
// Now overwrite mRTLastReportedPosition with our values
diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java
index c972476..df774b4 100644
--- a/core/java/android/view/ThreadedRenderer.java
+++ b/core/java/android/view/ThreadedRenderer.java
@@ -794,7 +794,8 @@
}
final long[] frameInfo = choreographer.mFrameInfo.mFrameInfo;
- int syncResult = nSyncAndDrawFrame(mNativeProxy, frameInfo, frameInfo.length);
+ int syncResult = nSyncAndDrawFrame(mNativeProxy, frameInfo, frameInfo.length,
+ mRootNode.mNativeRenderNode);
if ((syncResult & SYNC_LOST_SURFACE_REWARD_IF_FOUND) != 0) {
setEnabled(false);
attachInfo.mViewRootImpl.mSurface.release();
@@ -993,7 +994,8 @@
private static native void nSetLightCenter(long nativeProxy,
float lightX, float lightY, float lightZ);
private static native void nSetOpaque(long nativeProxy, boolean opaque);
- private static native int nSyncAndDrawFrame(long nativeProxy, long[] frameInfo, int size);
+ private static native int nSyncAndDrawFrame(long nativeProxy, long[] frameInfo, int size,
+ long rootRenderNode);
private static native void nDestroy(long nativeProxy, long rootRenderNode);
private static native void nRegisterAnimatingRenderNode(long rootRenderNode, long animatingNode);
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 83c6e9e..b723ffa8 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -2429,7 +2429,12 @@
* 1 PFLAG3_SCROLL_INDICATOR_START
* 1 PFLAG3_SCROLL_INDICATOR_END
* 1 PFLAG3_ASSIST_BLOCKED
- * 1111111 PFLAG3_POINTER_ICON_MASK
+ * 1 PFLAG3_POINTER_ICON_NULL
+ * 1 PFLAG3_POINTER_ICON_VALUE_START
+ * 11111111 PFLAG3_POINTER_ICON_MASK
+ * 1 PFLAG3_OVERLAPPING_RENDERING_FORCED_VALUE
+ * 1 PFLAG3_HAS_OVERLAPPING_RENDERING_FORCED
+ * 1 PFLAG3_TEMPORARY_DETACH
* |-------|-------|-------|-------|
*/
@@ -2518,8 +2523,6 @@
*/
static final int PFLAG3_SCROLL_INDICATOR_END = 0x2000;
- /* End of masks for mPrivateFlags3 */
-
static final int DRAG_MASK = PFLAG2_DRAG_CAN_ACCEPT | PFLAG2_DRAG_HOVERED;
static final int SCROLL_INDICATORS_NONE = 0x0000;
@@ -2651,6 +2654,31 @@
private static final int PFLAG3_POINTER_ICON_VALUE_START = 2 << PFLAG3_POINTER_ICON_LSHIFT;
/**
+ * Whether this view has rendered elements that overlap (see {@link
+ * #hasOverlappingRendering()}, {@link #forceHasOverlappingRendering(boolean)}, and
+ * {@link #getHasOverlappingRendering()} ). The value in this bit is only valid when
+ * PFLAG3_HAS_OVERLAPPING_RENDERING_FORCED has been set. Otherwise, the value is
+ * determined by whatever {@link #hasOverlappingRendering()} returns.
+ */
+ private static final int PFLAG3_OVERLAPPING_RENDERING_FORCED_VALUE = 0x800000;
+
+ /**
+ * Whether {@link #forceHasOverlappingRendering(boolean)} has been called. When true, value
+ * in PFLAG3_OVERLAPPING_RENDERING_FORCED_VALUE is valid.
+ */
+ private static final int PFLAG3_HAS_OVERLAPPING_RENDERING_FORCED = 0x1000000;
+
+ /**
+ * Flag indicating that the view is temporarily detached from the parent view.
+ *
+ * @see #onStartTemporaryDetach()
+ * @see #onFinishTemporaryDetach()
+ */
+ static final int PFLAG3_TEMPORARY_DETACH = 0x2000000;
+
+ /* End of masks for mPrivateFlags3 */
+
+ /**
* Always allow a user to over-scroll this view, provided it is a
* view that can scroll.
*
@@ -3871,6 +3899,7 @@
* cleanup.
*/
final RenderNode mRenderNode;
+ private Runnable mRenderNodeDetachedCallback;
/**
* Set to true when the view is sending hover accessibility events because it
@@ -4516,6 +4545,12 @@
}
}
break;
+ case R.styleable.View_forceHasOverlappingRendering:
+ if (a.peekValue(attr) != null) {
+ forceHasOverlappingRendering(a.getBoolean(attr, true));
+ }
+ break;
+
}
}
@@ -9710,9 +9745,20 @@
}
/**
- * @hide
+ * @return {@code true} when the View is in the state between {@link #onStartTemporaryDetach()}
+ * and {@link #onFinishTemporaryDetach()}.
*/
+ public final boolean isTemporarilyDetached() {
+ return (mPrivateFlags3 & PFLAG3_TEMPORARY_DETACH) != 0;
+ }
+
+ /**
+ * Dispatch {@link #onStartTemporaryDetach()} to this View and its direct children if this is
+ * a container View.
+ */
+ @CallSuper
public void dispatchStartTemporaryDetach() {
+ mPrivateFlags3 |= PFLAG3_TEMPORARY_DETACH;
onStartTemporaryDetach();
}
@@ -9728,10 +9774,13 @@
}
/**
- * @hide
+ * Dispatch {@link #onFinishTemporaryDetach()} to this View and its direct children if this is
+ * a container View.
*/
+ @CallSuper
public void dispatchFinishTemporaryDetach() {
onFinishTemporaryDetach();
+ mPrivateFlags3 &= ~PFLAG3_TEMPORARY_DETACH;
}
/**
@@ -12116,6 +12165,42 @@
}
/**
+ * Sets the behavior for overlapping rendering for this view (see {@link
+ * #hasOverlappingRendering()} for more details on this behavior). Calling this method
+ * is an alternative to overriding {@link #hasOverlappingRendering()} in a subclass,
+ * providing the value which is then used internally. That is, when {@link
+ * #forceHasOverlappingRendering(boolean)} is called, the value of {@link
+ * #hasOverlappingRendering()} is ignored and the value passed into this method is used
+ * instead.
+ *
+ * @param hasOverlappingRendering The value for overlapping rendering to be used internally
+ * instead of that returned by {@link #hasOverlappingRendering()}.
+ *
+ * @attr ref android.R.styleable#View_forceHasOverlappingRendering
+ */
+ public void forceHasOverlappingRendering(boolean hasOverlappingRendering) {
+ mPrivateFlags3 |= PFLAG3_HAS_OVERLAPPING_RENDERING_FORCED;
+ if (hasOverlappingRendering) {
+ mPrivateFlags3 |= PFLAG3_OVERLAPPING_RENDERING_FORCED_VALUE;
+ } else {
+ mPrivateFlags3 &= ~PFLAG3_OVERLAPPING_RENDERING_FORCED_VALUE;
+ }
+ }
+
+ /**
+ * Returns the value for overlapping rendering that is used internally. This is either
+ * the value passed into {@link #forceHasOverlappingRendering(boolean)}, if called, or
+ * the return value of {@link #hasOverlappingRendering()}, otherwise.
+ *
+ * @return The value for overlapping rendering being used internally.
+ */
+ public final boolean getHasOverlappingRendering() {
+ return (mPrivateFlags3 & PFLAG3_HAS_OVERLAPPING_RENDERING_FORCED) != 0 ?
+ (mPrivateFlags3 & PFLAG3_OVERLAPPING_RENDERING_FORCED_VALUE) != 0 :
+ hasOverlappingRendering();
+ }
+
+ /**
* Returns whether this View has content which overlaps.
*
* <p>This function, intended to be overridden by specific View types, is an optimization when
@@ -12131,6 +12216,9 @@
* necessitates that a View return true if it uses the methods internally without passing the
* {@link Canvas#CLIP_TO_LAYER_SAVE_FLAG}.</p>
*
+ * <p><strong>Note:</strong> The return value of this method is ignored if {@link
+ * #forceHasOverlappingRendering(boolean)} has been called on this view.</p>
+ *
* @return true if the content in this view might overlap, false otherwise.
*/
@ViewDebug.ExportedProperty(category = "drawing")
@@ -15123,6 +15211,7 @@
protected void onDetachedFromWindowInternal() {
mPrivateFlags &= ~PFLAG_CANCEL_NEXT_UP_EVENT;
mPrivateFlags3 &= ~PFLAG3_IS_LAID_OUT;
+ mPrivateFlags3 &= ~PFLAG3_TEMPORARY_DETACH;
removeUnsetPressCallback();
removeLongPressCallback();
@@ -15945,6 +16034,27 @@
}
/**
+ * Called when the passed RenderNode is removed from the draw tree
+ * @hide
+ */
+ public void onRenderNodeDetached(RenderNode renderNode) {
+ if (renderNode == mRenderNode && mRenderNodeDetachedCallback != null) {
+ mRenderNodeDetachedCallback.run();
+ }
+ }
+
+ /**
+ * Set callback for functor detach. Exposed to WebView through WebViewDelegate.
+ * Should not be used otherwise.
+ * @hide
+ */
+ public final Runnable setRenderNodeDetachedCallback(@Nullable Runnable callback) {
+ Runnable oldCallback = mRenderNodeDetachedCallback;
+ mRenderNodeDetachedCallback = callback;
+ return oldCallback;
+ }
+
+ /**
* <p>Calling this method is equivalent to calling <code>getDrawingCache(false)</code>.</p>
*
* @return A non-scaled bitmap representing this view or null if cache is disabled.
@@ -16235,8 +16345,10 @@
/**
* Create a snapshot of the view into a bitmap. We should probably make
* some form of this public, but should think about the API.
+ *
+ * @hide
*/
- Bitmap createSnapshot(Bitmap.Config quality, int backgroundColor, boolean skipChildren) {
+ public Bitmap createSnapshot(Bitmap.Config quality, int backgroundColor, boolean skipChildren) {
int width = mRight - mLeft;
int height = mBottom - mTop;
@@ -16566,7 +16678,7 @@
*/
void setDisplayListProperties(RenderNode renderNode) {
if (renderNode != null) {
- renderNode.setHasOverlappingRendering(hasOverlappingRendering());
+ renderNode.setHasOverlappingRendering(getHasOverlappingRendering());
renderNode.setClipToBounds(mParent instanceof ViewGroup
&& ((ViewGroup) mParent).getClipChildren());
@@ -16855,9 +16967,14 @@
} else {
// use layer paint to draw the bitmap, merging the two alphas, but also restore
int layerPaintAlpha = mLayerPaint != null ? mLayerPaint.getAlpha() : 255;
- mLayerPaint.setAlpha((int) (alpha * layerPaintAlpha));
+ if (mLayerPaint == null && alpha < 1) {
+ mLayerPaint = new Paint();
+ mLayerPaint.setAlpha((int) (alpha * layerPaintAlpha));
+ }
canvas.drawBitmap(cache, 0.0f, 0.0f, mLayerPaint);
- mLayerPaint.setAlpha(layerPaintAlpha);
+ if (mLayerPaint != null) {
+ mLayerPaint.setAlpha(layerPaintAlpha);
+ }
}
}
@@ -18001,13 +18118,7 @@
* to clear the previous drawable. setVisible first while we still have the callback set.
*/
if (mBackground != null) {
- // It's possible for this method to be invoked from the View constructor before
- // subclass constructors have run. Drawables can and should trigger invalidations
- // and other activity with their callback on visibility changes, which shouldn't
- // happen before subclass constructors finish. However, we won't have set the
- // drawable as visible until the view becomes attached. This guard below keeps
- // multiple calls to this method from constructors from causing issues.
- if (mBackground.isVisible()) {
+ if (isAttachedToWindow()) {
mBackground.setVisible(false, false);
}
mBackground.setCallback(null);
@@ -18242,13 +18353,7 @@
}
if (mForegroundInfo.mDrawable != null) {
- // It's possible for this method to be invoked from the View constructor before
- // subclass constructors have run. Drawables can and should trigger invalidations
- // and other activity with their callback on visibility changes, which shouldn't
- // happen before subclass constructors finish. However, we won't have set the
- // drawable as visible until the view becomes attached. This guard below keeps
- // multiple calls to this method from constructors from causing issues.
- if (mForegroundInfo.mDrawable.isVisible()) {
+ if (isAttachedToWindow()) {
mForegroundInfo.mDrawable.setVisible(false, false);
}
mForegroundInfo.mDrawable.setCallback(null);
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 816d9c4..3f7bbdf 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -3251,8 +3251,11 @@
}
}
+ /**
+ * @hide
+ */
@Override
- Bitmap createSnapshot(Bitmap.Config quality, int backgroundColor, boolean skipChildren) {
+ public Bitmap createSnapshot(Bitmap.Config quality, int backgroundColor, boolean skipChildren) {
int count = mChildrenCount;
int[] visibilities = null;
@@ -3262,7 +3265,8 @@
View child = getChildAt(i);
visibilities[i] = child.getVisibility();
if (visibilities[i] == View.VISIBLE) {
- child.setVisibility(INVISIBLE);
+ child.mViewFlags = (child.mViewFlags & ~View.VISIBILITY_MASK)
+ | (View.INVISIBLE & View.VISIBILITY_MASK);
}
}
}
@@ -3271,7 +3275,9 @@
if (skipChildren) {
for (int i = 0; i < count; i++) {
- getChildAt(i).setVisibility(visibilities[i]);
+ View child = getChildAt(i);
+ child.mViewFlags = (child.mViewFlags & ~View.VISIBILITY_MASK)
+ | (visibilities[i] & View.VISIBILITY_MASK);
}
}
@@ -6749,7 +6755,8 @@
@Override
public void onNestedScroll(View target, int dxConsumed, int dyConsumed,
int dxUnconsumed, int dyUnconsumed) {
- // Do nothing
+ // Re-dispatch up the tree by default
+ dispatchNestedScroll(dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed, null);
}
/**
@@ -6757,7 +6764,8 @@
*/
@Override
public void onNestedPreScroll(View target, int dx, int dy, int[] consumed) {
- // Do nothing
+ // Re-dispatch up the tree by default
+ dispatchNestedPreScroll(dx, dy, consumed, null);
}
/**
@@ -6765,7 +6773,8 @@
*/
@Override
public boolean onNestedFling(View target, float velocityX, float velocityY, boolean consumed) {
- return false;
+ // Re-dispatch up the tree by default
+ return dispatchNestedFling(velocityX, velocityY, consumed);
}
/**
@@ -6773,7 +6782,8 @@
*/
@Override
public boolean onNestedPreFling(View target, float velocityX, float velocityY) {
- return false;
+ // Re-dispatch up the tree by default
+ return dispatchNestedPreFling(velocityX, velocityY);
}
/**
diff --git a/core/java/android/view/ViewPropertyAnimator.java b/core/java/android/view/ViewPropertyAnimator.java
index f18b7ac..c604234 100644
--- a/core/java/android/view/ViewPropertyAnimator.java
+++ b/core/java/android/view/ViewPropertyAnimator.java
@@ -1110,6 +1110,13 @@
@Override
public void onAnimationEnd(Animator animation) {
mView.setHasTransientState(false);
+ if (mAnimatorCleanupMap != null) {
+ Runnable r = mAnimatorCleanupMap.get(animation);
+ if (r != null) {
+ r.run();
+ }
+ mAnimatorCleanupMap.remove(animation);
+ }
if (mListener != null) {
mListener.onAnimationEnd(animation);
}
@@ -1120,13 +1127,6 @@
}
mAnimatorOnEndMap.remove(animation);
}
- if (mAnimatorCleanupMap != null) {
- Runnable r = mAnimatorCleanupMap.get(animation);
- if (r != null) {
- r.run();
- }
- mAnimatorCleanupMap.remove(animation);
- }
mAnimatorMap.remove(animation);
}
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index fdf6979..5b2877f 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -85,6 +85,7 @@
import android.widget.Scroller;
import com.android.internal.R;
+import com.android.internal.annotations.GuardedBy;
import com.android.internal.os.IResultReceiver;
import com.android.internal.os.SomeArgs;
import com.android.internal.policy.PhoneFallbackEventHandler;
@@ -154,7 +155,12 @@
static final ArrayList<ComponentCallbacks> sConfigCallbacks = new ArrayList();
- final ArrayList<WindowCallbacks> mWindowCallbacks = new ArrayList();
+ /**
+ * This list must only be modified by the main thread, so a lock is only needed when changing
+ * the list or when accessing the list from a non-main thread.
+ */
+ @GuardedBy("mWindowCallbacks")
+ final ArrayList<WindowCallbacks> mWindowCallbacks = new ArrayList<>();
final Context mContext;
final IWindowSession mWindowSession;
final Display mDisplay;
@@ -768,7 +774,7 @@
* has invoked. If false, the functor may be invoked
* asynchronously.
*/
- public void invokeFunctor(long functor, boolean waitForCompletion) {
+ public static void invokeFunctor(long functor, boolean waitForCompletion) {
ThreadedRenderer.invokeFunctor(functor, waitForCompletion);
}
@@ -2120,7 +2126,7 @@
boolean cancelDraw = mAttachInfo.mTreeObserver.dispatchOnPreDraw() || !isViewVisible;
- if (!cancelDraw) {
+ if (!cancelDraw && !newSurface) {
if (mPendingTransitions != null && mPendingTransitions.size() > 0) {
for (int i = 0; i < mPendingTransitions.size(); ++i) {
mPendingTransitions.get(i).startChangingAnimations();
@@ -2169,7 +2175,6 @@
}
}
}
-
private void handleOutOfResourcesException(Surface.OutOfResourcesException e) {
Log.e(mTag, "OutOfResourcesException initializing HW surface", e);
try {
@@ -2437,10 +2442,8 @@
@Override
public void onHardwarePostDraw(DisplayListCanvas canvas) {
drawAccessibilityFocusedDrawableIfNeeded(canvas);
- synchronized (mWindowCallbacks) {
- for (int i = mWindowCallbacks.size() - 1; i >= 0; i--) {
- mWindowCallbacks.get(i).onPostDraw(canvas);
- }
+ for (int i = mWindowCallbacks.size() - 1; i >= 0; i--) {
+ mWindowCallbacks.get(i).onPostDraw(canvas);
}
}
@@ -3412,6 +3415,13 @@
updateConfiguration(config, false);
}
+ final boolean framesChanged = !mWinFrame.equals(args.arg1)
+ || !mPendingOverscanInsets.equals(args.arg5)
+ || !mPendingContentInsets.equals(args.arg2)
+ || !mPendingStableInsets.equals(args.arg6)
+ || !mPendingVisibleInsets.equals(args.arg3)
+ || !mPendingOutsets.equals(args.arg7);
+
mWinFrame.set((Rect) args.arg1);
mPendingOverscanInsets.set((Rect) args.arg5);
mPendingContentInsets.set((Rect) args.arg2);
@@ -3428,7 +3438,7 @@
mReportNextDraw = true;
}
- if (mView != null) {
+ if (mView != null && framesChanged) {
forceLayout(mView);
}
@@ -7092,11 +7102,9 @@
Rect stableInsets, int resizeMode) {
if (!mDragResizing) {
mDragResizing = true;
- synchronized (mWindowCallbacks) {
- for (int i = mWindowCallbacks.size() - 1; i >= 0; i--) {
- mWindowCallbacks.get(i).onWindowDragResizeStart(initialBounds, fullscreen,
- systemInsets, stableInsets, resizeMode);
- }
+ for (int i = mWindowCallbacks.size() - 1; i >= 0; i--) {
+ mWindowCallbacks.get(i).onWindowDragResizeStart(initialBounds, fullscreen,
+ systemInsets, stableInsets, resizeMode);
}
mFullRedrawNeeded = true;
}
@@ -7108,10 +7116,8 @@
private void endDragResizing() {
if (mDragResizing) {
mDragResizing = false;
- synchronized (mWindowCallbacks) {
- for (int i = mWindowCallbacks.size() - 1; i >= 0; i--) {
- mWindowCallbacks.get(i).onWindowDragResizeEnd();
- }
+ for (int i = mWindowCallbacks.size() - 1; i >= 0; i--) {
+ mWindowCallbacks.get(i).onWindowDragResizeEnd();
}
mFullRedrawNeeded = true;
}
@@ -7119,13 +7125,11 @@
private boolean updateContentDrawBounds() {
boolean updated = false;
- synchronized (mWindowCallbacks) {
- for (int i = mWindowCallbacks.size() - 1; i >= 0; i--) {
- updated |= mWindowCallbacks.get(i).onContentDrawn(
- mWindowAttributes.surfaceInsets.left,
- mWindowAttributes.surfaceInsets.top,
- mWidth, mHeight);
- }
+ for (int i = mWindowCallbacks.size() - 1; i >= 0; i--) {
+ updated |= mWindowCallbacks.get(i).onContentDrawn(
+ mWindowAttributes.surfaceInsets.left,
+ mWindowAttributes.surfaceInsets.top,
+ mWidth, mHeight);
}
return updated | (mDragResizing && mReportNextDraw);
}
@@ -7134,10 +7138,8 @@
if (mReportNextDraw) {
mWindowDrawCountDown = new CountDownLatch(mWindowCallbacks.size());
}
- synchronized (mWindowCallbacks) {
- for (int i = mWindowCallbacks.size() - 1; i >= 0; i--) {
- mWindowCallbacks.get(i).onRequestDraw(mReportNextDraw);
- }
+ for (int i = mWindowCallbacks.size() - 1; i >= 0; i--) {
+ mWindowCallbacks.get(i).onRequestDraw(mReportNextDraw);
}
}
diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java
index 36ee3e6..2f3f0bf 100644
--- a/core/java/android/view/Window.java
+++ b/core/java/android/view/Window.java
@@ -298,7 +298,7 @@
private boolean mDestroyed;
- private boolean mOverlayWithDecorCaption = false;
+ private boolean mOverlayWithDecorCaptionEnabled = false;
// The current window attributes.
private final WindowManager.LayoutParams mWindowAttributes =
@@ -2139,13 +2139,13 @@
* down. This affects only freeform windows since they display the caption.
* @hide
*/
- public void setOverlayDecorCaption(boolean overlayCaption) {
- mOverlayWithDecorCaption = overlayCaption;
+ public void setOverlayWithDecorCaptionEnabled(boolean enabled) {
+ mOverlayWithDecorCaptionEnabled = enabled;
}
/** @hide */
- public boolean getOverlayDecorCaption() {
- return mOverlayWithDecorCaption;
+ public boolean isOverlayWithDecorCaptionEnabled() {
+ return mOverlayWithDecorCaptionEnabled;
}
/** @hide */
@@ -2181,7 +2181,7 @@
* Called when the activity changes from fullscreen mode to multi-window mode and visa-versa.
* @hide
*/
- public abstract void onMultiWindowChanged();
+ public abstract void onMultiWindowModeChanged();
/**
* Called when the activity just relaunched.
diff --git a/core/java/android/view/WindowInfo.java b/core/java/android/view/WindowInfo.java
index b721074..737e4607 100644
--- a/core/java/android/view/WindowInfo.java
+++ b/core/java/android/view/WindowInfo.java
@@ -44,6 +44,8 @@
public boolean focused;
public final Rect boundsInScreen = new Rect();
public List<IBinder> childTokens;
+ public CharSequence title;
+ public int accessibilityIdOfAnchor = View.NO_ID;
private WindowInfo() {
/* do nothing - hide constructor */
@@ -65,6 +67,8 @@
window.parentToken = other.parentToken;
window.focused = other.focused;
window.boundsInScreen.set(other.boundsInScreen);
+ window.title = other.title;
+ window.accessibilityIdOfAnchor = other.accessibilityIdOfAnchor;
if (other.childTokens != null && !other.childTokens.isEmpty()) {
if (window.childTokens == null) {
@@ -95,6 +99,8 @@
parcel.writeStrongBinder(parentToken);
parcel.writeInt(focused ? 1 : 0);
boundsInScreen.writeToParcel(parcel, flags);
+ parcel.writeCharSequence(title);
+ parcel.writeInt(accessibilityIdOfAnchor);
if (childTokens != null && !childTokens.isEmpty()) {
parcel.writeInt(1);
@@ -108,13 +114,15 @@
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("WindowInfo[");
- builder.append("type=").append(type);
+ builder.append("title=").append(title);
+ builder.append(", type=").append(type);
builder.append(", layer=").append(layer);
builder.append(", token=").append(token);
builder.append(", bounds=").append(boundsInScreen);
builder.append(", parent=").append(parentToken);
builder.append(", focused=").append(focused);
builder.append(", children=").append(childTokens);
+ builder.append(", accessibility anchor=").append(accessibilityIdOfAnchor);
builder.append(']');
return builder.toString();
}
@@ -126,6 +134,8 @@
parentToken = parcel.readStrongBinder();
focused = (parcel.readInt() == 1);
boundsInScreen.readFromParcel(parcel);
+ title = parcel.readCharSequence();
+ accessibilityIdOfAnchor = parcel.readInt();
final boolean hasChildren = (parcel.readInt() == 1);
if (hasChildren) {
diff --git a/core/java/android/view/WindowInsets.java b/core/java/android/view/WindowInsets.java
index 929fdac..750931a 100644
--- a/core/java/android/view/WindowInsets.java
+++ b/core/java/android/view/WindowInsets.java
@@ -91,6 +91,7 @@
mWindowDecorInsetsConsumed = src.mWindowDecorInsetsConsumed;
mStableInsetsConsumed = src.mStableInsetsConsumed;
mIsRound = src.mIsRound;
+ mAlwaysConsumeNavBar = src.mAlwaysConsumeNavBar;
}
/** @hide */
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 03dcf99..c372c30 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -1693,6 +1693,14 @@
*/
public long userActivityTimeout = -1;
+ /**
+ * For windows with an anchor (e.g. PopupWindow), keeps track of the View that anchors the
+ * window.
+ *
+ * @hide
+ */
+ public int accessibilityIdOfAnchor = -1;
+
public LayoutParams() {
super(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
type = TYPE_APPLICATION;
@@ -1799,6 +1807,7 @@
out.writeInt(surfaceInsets.bottom);
out.writeInt(hasManualSurfaceInsets ? 1 : 0);
out.writeInt(needsMenuKey);
+ out.writeInt(accessibilityIdOfAnchor);
}
public static final Parcelable.Creator<LayoutParams> CREATOR
@@ -1849,6 +1858,7 @@
surfaceInsets.bottom = in.readInt();
hasManualSurfaceInsets = in.readInt() != 0;
needsMenuKey = in.readInt();
+ accessibilityIdOfAnchor = in.readInt();
}
@SuppressWarnings({"PointlessBitwiseExpression"})
@@ -1888,6 +1898,8 @@
/** {@hide} */
public static final int PREFERRED_DISPLAY_MODE_ID = 1 << 23;
/** {@hide} */
+ public static final int ACCESSIBILITY_ANCHOR_CHANGED = 1 << 24;
+ /** {@hide} */
public static final int EVERYTHING_CHANGED = 0xffffffff;
// internal buffer to backup/restore parameters under compatibility mode.
@@ -2048,6 +2060,11 @@
changes |= NEEDS_MENU_KEY_CHANGED;
}
+ if (accessibilityIdOfAnchor != o.accessibilityIdOfAnchor) {
+ accessibilityIdOfAnchor = o.accessibilityIdOfAnchor;
+ changes |= ACCESSIBILITY_ANCHOR_CHANGED;
+ }
+
return changes;
}
diff --git a/core/java/android/view/WindowManagerInternal.java b/core/java/android/view/WindowManagerInternal.java
index c22d60d..3ad730b 100644
--- a/core/java/android/view/WindowManagerInternal.java
+++ b/core/java/android/view/WindowManagerInternal.java
@@ -16,6 +16,7 @@
package android.view;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.graphics.Rect;
import android.graphics.Region;
@@ -157,6 +158,15 @@
public abstract void setMagnificationSpec(MagnificationSpec spec);
/**
+ * Obtains the magnified and available regions.
+ *
+ * @param outMagnified the currently magnified region
+ * @param outAvailable the region available for magnification
+ */
+ public abstract void getMagnificationRegions(@NonNull Region outMagnified,
+ @NonNull Region outAvailable);
+
+ /**
* Gets the magnification and translation applied to a window given its token.
* Not all windows are magnified and the window manager policy determines which
* windows are magnified. The returned result also takes into account the compat
diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java
index c1392fe..23b0df2 100644
--- a/core/java/android/view/WindowManagerPolicy.java
+++ b/core/java/android/view/WindowManagerPolicy.java
@@ -415,7 +415,7 @@
* Returns true if the window is current in multi-windowing mode. i.e. it shares the
* screen with other application windows.
*/
- public boolean inMultiWindowMode();
+ public boolean isInMultiWindowMode();
}
/**
diff --git a/core/java/android/view/accessibility/AccessibilityEvent.java b/core/java/android/view/accessibility/AccessibilityEvent.java
index 2cde03d..f8a13a3 100644
--- a/core/java/android/view/accessibility/AccessibilityEvent.java
+++ b/core/java/android/view/accessibility/AccessibilityEvent.java
@@ -240,10 +240,12 @@
* <li>{@link #getMovementGranularity()} - Sets the granularity at which a view's text
* was traversed.</li>
* <li>{@link #getText()} - The text of the source's sub-tree.</li>
- * <li>{@link #getFromIndex()} - The start of the next/previous text at the specified granularity
- * - inclusive.</li>
- * <li>{@link #getToIndex()} - The end of the next/previous text at the specified granularity
- * - exclusive.</li>
+ * <li>{@link #getFromIndex()} - The start the text that was skipped over in this movement.
+ * This is the starting point when moving forward through the text, but not when moving
+ * back.</li>
+ * <li>{@link #getToIndex()} - The end of the text that was skipped over in this movement.
+ * This is the ending point when moving forward through the text, but not when moving
+ * back.</li>
* <li>{@link #isPassword()} - Whether the source is password.</li>
* <li>{@link #isEnabled()} - Whether the source is enabled.</li>
* <li>{@link #getContentDescription()} - The content description of the source.</li>
diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
index bdaf291..1482111 100644
--- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java
+++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
@@ -2926,8 +2926,10 @@
mInputType = other.mInputType;
mLiveRegion = other.mLiveRegion;
mDrawingOrderInParent = other.mDrawingOrderInParent;
- if (other.mExtras != null && !other.mExtras.isEmpty()) {
- getExtras().putAll(other.mExtras);
+ if (other.mExtras != null) {
+ mExtras = new Bundle(other.mExtras);
+ } else {
+ mExtras = null;
}
mRangeInfo = (other.mRangeInfo != null)
? RangeInfo.obtain(other.mRangeInfo) : null;
@@ -3006,7 +3008,9 @@
mDrawingOrderInParent = parcel.readInt();
if (parcel.readInt() == 1) {
- getExtras().putAll(parcel.readBundle());
+ mExtras = parcel.readBundle();
+ } else {
+ mExtras = null;
}
if (parcel.readInt() == 1) {
@@ -3073,9 +3077,7 @@
mTextSelectionEnd = UNDEFINED_SELECTION_INDEX;
mInputType = InputType.TYPE_NULL;
mLiveRegion = View.ACCESSIBILITY_LIVE_REGION_NONE;
- if (mExtras != null) {
- mExtras.clear();
- }
+ mExtras = null;
if (mRangeInfo != null) {
mRangeInfo.recycle();
mRangeInfo = null;
diff --git a/core/java/android/view/accessibility/AccessibilityWindowInfo.java b/core/java/android/view/accessibility/AccessibilityWindowInfo.java
index ad78b68..d0d4507 100644
--- a/core/java/android/view/accessibility/AccessibilityWindowInfo.java
+++ b/core/java/android/view/accessibility/AccessibilityWindowInfo.java
@@ -89,6 +89,8 @@
private int mParentId = UNDEFINED;
private final Rect mBoundsInScreen = new Rect();
private LongArray mChildIds;
+ private CharSequence mTitle;
+ private int mAnchorId = UNDEFINED;
private int mConnectionId = UNDEFINED;
@@ -97,6 +99,26 @@
}
/**
+ * Gets the title of the window.
+ *
+ * @return The title.
+ */
+ public CharSequence getTitle() {
+ return mTitle;
+ }
+
+ /**
+ * Sets the title of the window.
+ *
+ * @param title The title.
+ *
+ * @hide
+ */
+ public void setTitle(CharSequence title) {
+ mTitle = title;
+ }
+
+ /**
* Gets the type of the window.
*
* @return The type.
@@ -159,9 +181,35 @@
}
/**
- * Gets the parent window if such.
+ * Sets the anchor node's ID.
*
- * @return The parent window.
+ * @param anchorId The anchor's accessibility id in its window.
+ *
+ * @hide
+ */
+ public void setAnchorId(int anchorId) {
+ mAnchorId = anchorId;
+ }
+
+ /**
+ * Gets the node that anchors this window to another.
+ *
+ * @return The anchor node, or {@code null} if none exists.
+ */
+ public AccessibilityNodeInfo getAnchor() {
+ if ((mConnectionId == UNDEFINED) || (mAnchorId == UNDEFINED) || (mParentId == UNDEFINED)) {
+ return null;
+ }
+
+ AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
+ return client.findAccessibilityNodeInfoByAccessibilityId(mConnectionId,
+ mParentId, mAnchorId, true, 0);
+ }
+
+ /**
+ * Gets the parent window.
+ *
+ * @return The parent window, or {@code null} if none exists.
*/
public AccessibilityWindowInfo getParent() {
if (mConnectionId == UNDEFINED || mParentId == UNDEFINED) {
@@ -370,6 +418,8 @@
infoClone.mId = info.mId;
infoClone.mParentId = info.mParentId;
infoClone.mBoundsInScreen.set(info.mBoundsInScreen);
+ infoClone.mTitle = info.mTitle;
+ infoClone.mAnchorId = info.mAnchorId;
if (info.mChildIds != null && info.mChildIds.size() > 0) {
if (infoClone.mChildIds == null) {
@@ -410,6 +460,8 @@
parcel.writeInt(mId);
parcel.writeInt(mParentId);
mBoundsInScreen.writeToParcel(parcel, flags);
+ parcel.writeCharSequence(mTitle);
+ parcel.writeInt(mAnchorId);
final LongArray childIds = mChildIds;
if (childIds == null) {
@@ -432,6 +484,8 @@
mId = parcel.readInt();
mParentId = parcel.readInt();
mBoundsInScreen.readFromParcel(parcel);
+ mTitle = parcel.readCharSequence();
+ mAnchorId = parcel.readInt();
final int childCount = parcel.readInt();
if (childCount > 0) {
@@ -471,6 +525,7 @@
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("AccessibilityWindowInfo[");
+ builder.append("title=").append(mTitle);
builder.append("id=").append(mId);
builder.append(", type=").append(typeToString(mType));
builder.append(", layer=").append(mLayer);
@@ -494,6 +549,7 @@
builder.append(']');
} else {
builder.append(", hasParent=").append(mParentId != UNDEFINED);
+ builder.append(", isAnchored=").append(mAnchorId != UNDEFINED);
builder.append(", hasChildren=").append(mChildIds != null
&& mChildIds.size() > 0);
}
@@ -515,6 +571,8 @@
mChildIds.clear();
}
mConnectionId = UNDEFINED;
+ mAnchorId = UNDEFINED;
+ mTitle = null;
}
/**
diff --git a/core/java/android/view/inputmethod/BaseInputConnection.java b/core/java/android/view/inputmethod/BaseInputConnection.java
index a3c49c5..89dec2d 100644
--- a/core/java/android/view/inputmethod/BaseInputConnection.java
+++ b/core/java/android/view/inputmethod/BaseInputConnection.java
@@ -16,6 +16,7 @@
package android.view.inputmethod;
+import android.annotation.CallSuper;
import android.content.Context;
import android.content.res.TypedArray;
import android.os.Bundle;
@@ -154,12 +155,11 @@
}
/**
- * Called when this InputConnection is no longer used by the InputMethodManager.
- *
- * @hide
+ * Default implementation calls {@link #finishComposingText()}.
*/
- public void reportFinish() {
- // Intentionally empty
+ @CallSuper
+ public void closeConnection() {
+ finishComposingText();
}
/**
diff --git a/core/java/android/view/inputmethod/InputConnection.java b/core/java/android/view/inputmethod/InputConnection.java
index 8002a8e..9f66429 100644
--- a/core/java/android/view/inputmethod/InputConnection.java
+++ b/core/java/android/view/inputmethod/InputConnection.java
@@ -45,6 +45,8 @@
* was introduced in {@link android.os.Build.VERSION_CODES#N}.</li>
* <li>{@link #getHandler()}}, which was introduced in
* {@link android.os.Build.VERSION_CODES#N}.</li>
+ * <li>{@link #closeConnection()}}, which was introduced in
+ * {@link android.os.Build.VERSION_CODES#N}.</li>
* </ul>
*
* <h3>Implementing an IME or an editor</h3>
@@ -820,4 +822,18 @@
* @return {@code null} to use the default {@link Handler}.
*/
public Handler getHandler();
+
+ /**
+ * Called by the system up to only once to notify that the system is about to invalidate
+ * connection between the input method and the application.
+ *
+ * <p><strong>Editor authors</strong>: You can clear all the nested batch edit right now and
+ * you no longer need to handle subsequent callbacks on this connection, including
+ * {@link #beginBatchEdit()}}. Note that although the system tries to call this method whenever
+ * possible, there may be a chance that this method is not called in some exceptional
+ * situations.</p>
+ *
+ * <p>Note: This does nothing when called from input methods.</p>
+ */
+ public void closeConnection();
}
diff --git a/core/java/android/view/inputmethod/InputConnectionInspector.java b/core/java/android/view/inputmethod/InputConnectionInspector.java
index 46b2c3e..118a61f 100644
--- a/core/java/android/view/inputmethod/InputConnectionInspector.java
+++ b/core/java/android/view/inputmethod/InputConnectionInspector.java
@@ -73,6 +73,11 @@
* {@link android.os.Build.VERSION_CODES#N} and later.
*/
int GET_HANDLER = 1 << 5;
+ /**
+ * {@link InputConnection#closeConnection()}} is available in
+ * {@link android.os.Build.VERSION_CODES#N} and later.
+ */
+ int CLOSE_CONNECTION = 1 << 6;
}
private static final Map<Class, Integer> sMissingMethodsMap = Collections.synchronizedMap(
@@ -119,6 +124,9 @@
if (!hasGetHandler(clazz)) {
flags |= MissingMethodFlags.GET_HANDLER;
}
+ if (!hasCloseConnection(clazz)) {
+ flags |= MissingMethodFlags.CLOSE_CONNECTION;
+ }
sMissingMethodsMap.put(clazz, flags);
return flags;
}
@@ -178,6 +186,15 @@
}
}
+ private static boolean hasCloseConnection(@NonNull final Class clazz) {
+ try {
+ final Method method = clazz.getMethod("closeConnection");
+ return !Modifier.isAbstract(method.getModifiers());
+ } catch (NoSuchMethodException e) {
+ return false;
+ }
+ }
+
public static String getMissingMethodFlagsAsString(@MissingMethodFlags final int flags) {
final StringBuilder sb = new StringBuilder();
boolean isEmpty = true;
@@ -219,6 +236,12 @@
}
sb.append("getHandler()");
}
+ if ((flags & MissingMethodFlags.CLOSE_CONNECTION) != 0) {
+ if (!isEmpty) {
+ sb.append(",");
+ }
+ sb.append("closeConnection()");
+ }
return sb.toString();
}
}
diff --git a/core/java/android/view/inputmethod/InputConnectionWrapper.java b/core/java/android/view/inputmethod/InputConnectionWrapper.java
index 381df49..e743f62 100644
--- a/core/java/android/view/inputmethod/InputConnectionWrapper.java
+++ b/core/java/android/view/inputmethod/InputConnectionWrapper.java
@@ -261,4 +261,12 @@
public Handler getHandler() {
return mTarget.getHandler();
}
+
+ /**
+ * {@inheritDoc}
+ * @throws NullPointerException if the target is {@code null}.
+ */
+ public void closeConnection() {
+ mTarget.closeConnection();
+ }
}
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index f6f88f2..4f4c6b9 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -493,12 +493,7 @@
// Check focus again in case that "onWindowFocus" is called before
// handling this message.
if (mServedView != null && mServedView.hasWindowFocus()) {
- // Please note that this handler thread could be different
- // from a thread that created mServedView. That could happen
- // the current activity is running in the system process.
- // In that case, we really should not call
- // mServedInputConnectionWrapper.finishComposingText().
- if (checkFocusNoStartInput(mHasBeenInactive, false)) {
+ if (checkFocusNoStartInput(mHasBeenInactive)) {
final int reason = active ?
InputMethodClient.START_INPUT_REASON_ACTIVATED_BY_IMMS :
InputMethodClient.START_INPUT_REASON_DEACTIVATED_BY_IMMS;
@@ -549,7 +544,7 @@
// reportFinish() will take effect.
return;
}
- reportFinish();
+ closeConnection();
}
@Override
@@ -1371,12 +1366,12 @@
* @hide
*/
public void checkFocus() {
- if (checkFocusNoStartInput(false, true)) {
+ if (checkFocusNoStartInput(false)) {
startInputInner(InputMethodClient.START_INPUT_REASON_CHECK_FOCUS, null, 0, 0, 0);
}
}
- private boolean checkFocusNoStartInput(boolean forceNewFocus, boolean finishComposingText) {
+ private boolean checkFocusNoStartInput(boolean forceNewFocus) {
// This is called a lot, so short-circuit before locking.
if (mServedView == mNextServedView && !forceNewFocus) {
return false;
@@ -1410,7 +1405,7 @@
mServedConnecting = true;
}
- if (finishComposingText && ic != null) {
+ if (ic != null) {
ic.finishComposingText();
}
@@ -1456,7 +1451,7 @@
controlFlags |= CONTROL_WINDOW_FIRST;
}
- if (checkFocusNoStartInput(forceNewFocus, true)) {
+ if (checkFocusNoStartInput(forceNewFocus)) {
// We need to restart input on the current focus view. This
// should be done in conjunction with telling the system service
// about the window gaining focus, to help make the transition
diff --git a/core/java/android/webkit/WebViewDelegate.java b/core/java/android/webkit/WebViewDelegate.java
index 94dc03c..b6516c8 100644
--- a/core/java/android/webkit/WebViewDelegate.java
+++ b/core/java/android/webkit/WebViewDelegate.java
@@ -16,6 +16,8 @@
package android.webkit;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.app.ActivityThread;
import android.app.Application;
@@ -86,8 +88,7 @@
*/
public void invokeDrawGlFunctor(View containerView, long nativeDrawGLFunctor,
boolean waitForCompletion) {
- ViewRootImpl viewRootImpl = containerView.getViewRootImpl();
- viewRootImpl.invokeFunctor(nativeDrawGLFunctor, waitForCompletion);
+ ViewRootImpl.invokeFunctor(nativeDrawGLFunctor, waitForCompletion);
}
/**
@@ -110,6 +111,24 @@
}
/**
+ * Set the Runnable callback the DrawGlFunction functor is detached and free to be destroyed.
+ * This will replace the previous callback, if any.
+ *
+ * @param view The view to set the callback. Should be the view where onDraw inserted
+ * DrawGLFunctor.
+ * @param callback The new callback to set on the view.
+ * @throws IllegalArgumentException if view is null.
+ * @return The previous callback on this view.
+ */
+ public Runnable setDrawGlFunctionDetachedCallback(
+ @NonNull View view, @Nullable Runnable callback) {
+ if (view == null) {
+ throw new IllegalArgumentException("View cannot be null");
+ }
+ return view.setRenderNodeDetachedCallback(callback);
+ }
+
+ /**
* Detaches the draw GL functor.
*
* @param nativeDrawGLFunctor the pointer to the native functor that implements
diff --git a/core/java/android/webkit/WebViewFactory.java b/core/java/android/webkit/WebViewFactory.java
index f1bf890..0ac5731 100644
--- a/core/java/android/webkit/WebViewFactory.java
+++ b/core/java/android/webkit/WebViewFactory.java
@@ -21,7 +21,6 @@
import android.app.AppGlobals;
import android.app.Application;
import android.content.Context;
-import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
@@ -128,11 +127,6 @@
public MissingWebViewPackageException(Exception e) { super(e); }
}
- // TODO (gsennton) remove when committing webview xts test change
- public static String getWebViewPackageName() {
- return null;
- }
-
/**
* @hide
*/
@@ -566,20 +560,12 @@
return result;
}
- /**
- * Returns whether the entire package from an ACTION_PACKAGE_CHANGED intent was changed (rather
- * than just one of its components).
- * @hide
- */
- public static boolean entirePackageChanged(Intent intent) {
- String[] componentList =
- intent.getStringArrayExtra(Intent.EXTRA_CHANGED_COMPONENT_NAME_LIST);
- return Arrays.asList(componentList).contains(
- intent.getDataString().substring("package:".length()));
- }
+ private static String WEBVIEW_UPDATE_SERVICE_NAME = "webviewupdate";
- private static IWebViewUpdateService getUpdateService() {
- return IWebViewUpdateService.Stub.asInterface(ServiceManager.getService("webviewupdate"));
+ /** @hide */
+ public static IWebViewUpdateService getUpdateService() {
+ return IWebViewUpdateService.Stub.asInterface(
+ ServiceManager.getService(WEBVIEW_UPDATE_SERVICE_NAME));
}
private static native boolean nativeReserveAddressSpace(long addressSpaceToReserve);
diff --git a/core/java/android/webkit/WebViewProviderInfo.java b/core/java/android/webkit/WebViewProviderInfo.java
index 75ccf35..5d091c9 100644
--- a/core/java/android/webkit/WebViewProviderInfo.java
+++ b/core/java/android/webkit/WebViewProviderInfo.java
@@ -16,32 +16,20 @@
package android.webkit;
-import android.app.AppGlobals;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageInfo;
-import android.content.pm.PackageManager;
-import android.content.pm.Signature;
-import android.os.Build;
+import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;
-import android.util.AndroidRuntimeException;
-import android.util.Base64;
import java.util.Arrays;
-/** @hide */
-public class WebViewProviderInfo implements Parcelable {
+/**
+ * @hide
+ */
+@SystemApi
+public final class WebViewProviderInfo implements Parcelable {
- /**
- * @hide
- */
- public static class WebViewPackageNotFoundException extends AndroidRuntimeException {
- public WebViewPackageNotFoundException(String message) { super(message); }
- public WebViewPackageNotFoundException(Exception e) { super(e); }
- }
-
- public WebViewProviderInfo(String packageName, String description, boolean availableByDefault,
- boolean isFallback, String[] signatures) {
+ public WebViewProviderInfo(String packageName, String description,
+ boolean availableByDefault, boolean isFallback, String[] signatures) {
this.packageName = packageName;
this.description = description;
this.availableByDefault = availableByDefault;
@@ -49,92 +37,6 @@
this.signatures = signatures;
}
- private boolean hasValidSignature() {
- if (Build.IS_DEBUGGABLE)
- return true;
- Signature[] packageSignatures;
- try {
- // If no signature is declared, instead check whether the package is included in the
- // system.
- if (signatures == null || signatures.length == 0)
- return getPackageInfo().applicationInfo.isSystemApp();
-
- packageSignatures = getPackageInfo().signatures;
- } catch (WebViewPackageNotFoundException e) {
- return false;
- }
- if (packageSignatures.length != 1)
- return false;
-
- final byte[] packageSignature = packageSignatures[0].toByteArray();
- // Return whether the package signature matches any of the valid signatures
- for (String signature : signatures) {
- final byte[] validSignature = Base64.decode(signature, Base64.DEFAULT);
- if (Arrays.equals(packageSignature, validSignature))
- return true;
- }
- return false;
- }
-
- /**
- * Returns whether this provider is valid for use as a WebView provider.
- */
- public boolean isValidProvider() {
- ApplicationInfo applicationInfo;
- try {
- applicationInfo = getPackageInfo().applicationInfo;
- } catch (WebViewPackageNotFoundException e) {
- return false;
- }
- if (hasValidSignature() && WebViewFactory.getWebViewLibrary(applicationInfo) != null) {
- return true;
- }
- return false;
- }
-
- /**
- * Returns whether this package is enabled.
- * This state can be changed by the user from Settings->Apps
- */
- public boolean isEnabled() {
- try {
- // Explicitly fetch up-to-date package info here since the enabled-state of the package
- // might have changed since we last fetched its package info.
- updatePackageInfo();
- return getPackageInfo().applicationInfo.enabled;
- } catch (WebViewPackageNotFoundException e) {
- return false;
- }
- }
-
- /**
- * Returns whether the provider is always available as long as it is valid.
- * If this returns false, the provider will only be used if the user chose this provider.
- */
- public boolean isAvailableByDefault() {
- return availableByDefault;
- }
-
- public boolean isFallbackPackage() {
- return isFallback;
- }
-
- private void updatePackageInfo() {
- try {
- PackageManager pm = AppGlobals.getInitialApplication().getPackageManager();
- packageInfo = pm.getPackageInfo(packageName, PACKAGE_FLAGS);
- } catch (PackageManager.NameNotFoundException e) {
- throw new WebViewPackageNotFoundException(e);
- }
- }
-
- public PackageInfo getPackageInfo() {
- if (packageInfo == null) {
- updatePackageInfo();
- }
- return packageInfo;
- }
-
// aidl stuff
public static final Parcelable.Creator<WebViewProviderInfo> CREATOR =
new Parcelable.Creator<WebViewProviderInfo>() {
@@ -153,7 +55,6 @@
availableByDefault = (in.readInt() > 0);
isFallback = (in.readInt() > 0);
signatures = in.createStringArray();
- packageInfo = null;
}
@Override
@@ -171,16 +72,9 @@
}
// fields read from framework resource
- public String packageName;
- public String description;
- private boolean availableByDefault;
- private boolean isFallback;
-
- private String[] signatures;
-
- private PackageInfo packageInfo;
-
- // flags declaring we want extra info from the package manager
- private final static int PACKAGE_FLAGS = PackageManager.GET_META_DATA
- | PackageManager.GET_SIGNATURES | PackageManager.MATCH_DEBUG_TRIAGED_MISSING;
+ public final String packageName;
+ public final String description;
+ public final boolean availableByDefault;
+ public final boolean isFallback;
+ public final String[] signatures;
}
diff --git a/core/java/android/webkit/WebViewUpdateService.java b/core/java/android/webkit/WebViewUpdateService.java
new file mode 100644
index 0000000..4e83d88
--- /dev/null
+++ b/core/java/android/webkit/WebViewUpdateService.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.webkit;
+
+import android.annotation.SystemApi;
+import android.os.RemoteException;
+
+/**
+ * @hide
+ */
+@SystemApi
+public final class WebViewUpdateService {
+
+ private WebViewUpdateService () {}
+
+ /**
+ * Fetch all packages that could potentially implement WebView.
+ */
+ public static WebViewProviderInfo[] getAllWebViewPackages() {
+ try {
+ return getUpdateService().getAllWebViewPackages();
+ } catch (RemoteException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * Fetch all packages that could potentially implement WebView and are currently valid.
+ */
+ public static WebViewProviderInfo[] getValidWebViewPackages() {
+ try {
+ return getUpdateService().getValidWebViewPackages();
+ } catch (RemoteException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * Used by DevelopmentSetting to get the name of the WebView provider currently in use.
+ */
+ public static String getCurrentWebViewPackageName() {
+ try {
+ return getUpdateService().getCurrentWebViewPackageName();
+ } catch (RemoteException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private static IWebViewUpdateService getUpdateService() {
+ return WebViewFactory.getUpdateService();
+ }
+}
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index 7cbe8de..6e1dff9 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -5937,6 +5937,11 @@
public Handler getHandler() {
return getTarget().getHandler();
}
+
+ @Override
+ public void closeConnection() {
+ getTarget().closeConnection();
+ }
}
/**
diff --git a/core/java/android/widget/AccessibilityIterators.java b/core/java/android/widget/AccessibilityIterators.java
index a3d58a4..442ffa1 100644
--- a/core/java/android/widget/AccessibilityIterators.java
+++ b/core/java/android/widget/AccessibilityIterators.java
@@ -134,8 +134,8 @@
@Override
public int[] following(int offset) {
- final int textLegth = mText.length();
- if (textLegth <= 0) {
+ final int textLength = mText.length();
+ if (textLength <= 0) {
return null;
}
if (offset >= mText.length()) {
@@ -163,8 +163,8 @@
@Override
public int[] preceding(int offset) {
- final int textLegth = mText.length();
- if (textLegth <= 0) {
+ final int textLength = mText.length();
+ if (textLength <= 0) {
return null;
}
if (offset <= 0) {
@@ -181,8 +181,13 @@
final int pageHeight = mTempRect.height() - mView.getTotalPaddingTop()
- mView.getTotalPaddingBottom();
final int previousPageEndY = currentLineTop - pageHeight;
- final int currentPageStartLine = (previousPageEndY > 0) ?
- mLayout.getLineForVertical(previousPageEndY) + 1 : 0;
+ int currentPageStartLine = (previousPageEndY > 0) ?
+ mLayout.getLineForVertical(previousPageEndY) : 0;
+ // If we're at the end of text, we're at the end of the current line rather than the
+ // start of the next line, so we should move up one fewer lines than we would otherwise.
+ if (end == mText.length() && (currentPageStartLine < currentLine)) {
+ currentPageStartLine += 1;
+ }
final int start = getLineEdgeIndex(currentPageStartLine, DIRECTION_START);
diff --git a/core/java/android/widget/ArrayAdapter.java b/core/java/android/widget/ArrayAdapter.java
index 027f6d6..9d228cf 100644
--- a/core/java/android/widget/ArrayAdapter.java
+++ b/core/java/android/widget/ArrayAdapter.java
@@ -20,6 +20,7 @@
import android.annotation.IdRes;
import android.annotation.LayoutRes;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.content.Context;
import android.content.res.Resources;
import android.util.Log;
@@ -61,17 +62,13 @@
private final LayoutInflater mInflater;
- /**
- * Contains the list of objects that represent the data of this ArrayAdapter.
- * The content of this list is referred to as "the array" in the documentation.
- */
- private List<T> mObjects;
+ private final Context mContext;
/**
* The resource indicating what views to inflate to display the content of this
* array adapter.
*/
- private int mResource;
+ private final int mResource;
/**
* The resource indicating what views to inflate to display the content of this
@@ -80,7 +77,13 @@
private int mDropDownResource;
/**
- * If the inflated resource is not a TextView, {@link #mFieldId} is used to find
+ * Contains the list of objects that represent the data of this ArrayAdapter.
+ * The content of this list is referred to as "the array" in the documentation.
+ */
+ private List<T> mObjects;
+
+ /**
+ * If the inflated resource is not a TextView, {@code mFieldId} is used to find
* a TextView inside the inflated views hierarchy. This field must contain the
* identifier that matches the one defined in the resource file.
*/
@@ -92,8 +95,6 @@
*/
private boolean mNotifyOnChange = true;
- private Context mContext;
-
// A copy of the original mObjects array, initialized from and then used instead as soon as
// the mFilter ArrayFilter is used. mObjects will then only contain the filtered values.
private ArrayList<T> mOriginalValues;
@@ -109,8 +110,8 @@
* @param resource The resource ID for a layout file containing a TextView to use when
* instantiating views.
*/
- public ArrayAdapter(Context context, @LayoutRes int resource) {
- this(context, resource, 0, new ArrayList<T>());
+ public ArrayAdapter(@NonNull Context context, @LayoutRes int resource) {
+ this(context, resource, 0, new ArrayList<>());
}
/**
@@ -121,8 +122,9 @@
* instantiating views.
* @param textViewResourceId The id of the TextView within the layout resource to be populated
*/
- public ArrayAdapter(Context context, @LayoutRes int resource, @IdRes int textViewResourceId) {
- this(context, resource, textViewResourceId, new ArrayList<T>());
+ public ArrayAdapter(@NonNull Context context, @LayoutRes int resource,
+ @IdRes int textViewResourceId) {
+ this(context, resource, textViewResourceId, new ArrayList<>());
}
/**
@@ -133,7 +135,7 @@
* instantiating views.
* @param objects The objects to represent in the ListView.
*/
- public ArrayAdapter(Context context, @LayoutRes int resource, @NonNull T[] objects) {
+ public ArrayAdapter(@NonNull Context context, @LayoutRes int resource, @NonNull T[] objects) {
this(context, resource, 0, Arrays.asList(objects));
}
@@ -146,8 +148,8 @@
* @param textViewResourceId The id of the TextView within the layout resource to be populated
* @param objects The objects to represent in the ListView.
*/
- public ArrayAdapter(Context context, @LayoutRes int resource, @IdRes int textViewResourceId,
- @NonNull T[] objects) {
+ public ArrayAdapter(@NonNull Context context, @LayoutRes int resource,
+ @IdRes int textViewResourceId, @NonNull T[] objects) {
this(context, resource, textViewResourceId, Arrays.asList(objects));
}
@@ -159,7 +161,8 @@
* instantiating views.
* @param objects The objects to represent in the ListView.
*/
- public ArrayAdapter(Context context, @LayoutRes int resource, @NonNull List<T> objects) {
+ public ArrayAdapter(@NonNull Context context, @LayoutRes int resource,
+ @NonNull List<T> objects) {
this(context, resource, 0, objects);
}
@@ -172,8 +175,8 @@
* @param textViewResourceId The id of the TextView within the layout resource to be populated
* @param objects The objects to represent in the ListView.
*/
- public ArrayAdapter(Context context, @LayoutRes int resource, @IdRes int textViewResourceId,
- @NonNull List<T> objects) {
+ public ArrayAdapter(@NonNull Context context, @LayoutRes int resource,
+ @IdRes int textViewResourceId, @NonNull List<T> objects) {
mContext = context;
mInflater = LayoutInflater.from(context);
mResource = mDropDownResource = resource;
@@ -186,7 +189,7 @@
*
* @param object The object to add at the end of the array.
*/
- public void add(T object) {
+ public void add(@Nullable T object) {
synchronized (mLock) {
if (mOriginalValues != null) {
mOriginalValues.add(object);
@@ -201,8 +204,17 @@
* Adds the specified Collection at the end of the array.
*
* @param collection The Collection to add at the end of the array.
+ * @throws UnsupportedOperationException if the <tt>addAll</tt> operation
+ * is not supported by this list
+ * @throws ClassCastException if the class of an element of the specified
+ * collection prevents it from being added to this list
+ * @throws NullPointerException if the specified collection contains one
+ * or more null elements and this list does not permit null
+ * elements, or if the specified collection is null
+ * @throws IllegalArgumentException if some property of an element of the
+ * specified collection prevents it from being added to this list
*/
- public void addAll(Collection<? extends T> collection) {
+ public void addAll(@NonNull Collection<? extends T> collection) {
synchronized (mLock) {
if (mOriginalValues != null) {
mOriginalValues.addAll(collection);
@@ -235,7 +247,7 @@
* @param object The object to insert into the array.
* @param index The index at which the object must be inserted.
*/
- public void insert(T object, int index) {
+ public void insert(@Nullable T object, int index) {
synchronized (mLock) {
if (mOriginalValues != null) {
mOriginalValues.add(index, object);
@@ -251,7 +263,7 @@
*
* @param object The object to remove.
*/
- public void remove(T object) {
+ public void remove(@Nullable T object) {
synchronized (mLock) {
if (mOriginalValues != null) {
mOriginalValues.remove(object);
@@ -282,7 +294,7 @@
* @param comparator The comparator used to sort the objects contained
* in this adapter.
*/
- public void sort(Comparator<? super T> comparator) {
+ public void sort(@NonNull Comparator<? super T> comparator) {
synchronized (mLock) {
if (mOriginalValues != null) {
Collections.sort(mOriginalValues, comparator);
@@ -293,9 +305,6 @@
if (mNotifyOnChange) notifyDataSetChanged();
}
- /**
- * {@inheritDoc}
- */
@Override
public void notifyDataSetChanged() {
super.notifyDataSetChanged();
@@ -326,21 +335,17 @@
*
* @return The Context associated with this adapter.
*/
- public Context getContext() {
+ public @NonNull Context getContext() {
return mContext;
}
- /**
- * {@inheritDoc}
- */
+ @Override
public int getCount() {
return mObjects.size();
}
- /**
- * {@inheritDoc}
- */
- public T getItem(int position) {
+ @Override
+ public @Nullable T getItem(int position) {
return mObjects.get(position);
}
@@ -351,28 +356,25 @@
*
* @return The position of the specified item.
*/
- public int getPosition(T item) {
+ public int getPosition(@Nullable T item) {
return mObjects.indexOf(item);
}
- /**
- * {@inheritDoc}
- */
+ @Override
public long getItemId(int position) {
return position;
}
- /**
- * {@inheritDoc}
- */
- public View getView(int position, View convertView, ViewGroup parent) {
+ @Override
+ public @NonNull View getView(int position, @Nullable View convertView,
+ @NonNull ViewGroup parent) {
return createViewFromResource(mInflater, position, convertView, parent, mResource);
}
- private View createViewFromResource(LayoutInflater inflater, int position, View convertView,
- ViewGroup parent, int resource) {
- View view;
- TextView text;
+ private @NonNull View createViewFromResource(@NonNull LayoutInflater inflater, int position,
+ @Nullable View convertView, @NonNull ViewGroup parent, int resource) {
+ final View view;
+ final TextView text;
if (convertView == null) {
view = inflater.inflate(resource, parent, false);
@@ -387,6 +389,12 @@
} else {
// Otherwise, find the TextView field within the layout
text = (TextView) view.findViewById(mFieldId);
+
+ if (text == null) {
+ throw new RuntimeException("Failed to find view with ID "
+ + mContext.getResources().getResourceName(mFieldId)
+ + " in item layout");
+ }
}
} catch (ClassCastException e) {
Log.e("ArrayAdapter", "You must supply a resource ID for a TextView");
@@ -394,9 +402,9 @@
"ArrayAdapter requires the resource ID to be a TextView", e);
}
- T item = getItem(position);
+ final T item = getItem(position);
if (item instanceof CharSequence) {
- text.setText((CharSequence)item);
+ text.setText((CharSequence) item);
} else {
text.setText(item.toString());
}
@@ -426,7 +434,7 @@
* @see #getDropDownView(int, View, ViewGroup)
*/
@Override
- public void setDropDownViewTheme(Resources.Theme theme) {
+ public void setDropDownViewTheme(@Nullable Resources.Theme theme) {
if (theme == null) {
mDropDownInflater = null;
} else if (theme == mInflater.getContext().getTheme()) {
@@ -438,12 +446,13 @@
}
@Override
- public Resources.Theme getDropDownViewTheme() {
+ public @Nullable Resources.Theme getDropDownViewTheme() {
return mDropDownInflater == null ? null : mDropDownInflater.getContext().getTheme();
}
@Override
- public View getDropDownView(int position, View convertView, ViewGroup parent) {
+ public View getDropDownView(int position, @Nullable View convertView,
+ @NonNull ViewGroup parent) {
final LayoutInflater inflater = mDropDownInflater == null ? mInflater : mDropDownInflater;
return createViewFromResource(inflater, position, convertView, parent, mDropDownResource);
}
@@ -458,16 +467,14 @@
*
* @return An ArrayAdapter<CharSequence>.
*/
- public static ArrayAdapter<CharSequence> createFromResource(Context context,
+ public static @NonNull ArrayAdapter<CharSequence> createFromResource(@NonNull Context context,
@ArrayRes int textArrayResId, @LayoutRes int textViewResId) {
- CharSequence[] strings = context.getResources().getTextArray(textArrayResId);
- return new ArrayAdapter<CharSequence>(context, textViewResId, strings);
+ final CharSequence[] strings = context.getResources().getTextArray(textArrayResId);
+ return new ArrayAdapter<>(context, textViewResId, strings);
}
- /**
- * {@inheritDoc}
- */
- public Filter getFilter() {
+ @Override
+ public @NonNull Filter getFilter() {
if (mFilter == null) {
mFilter = new ArrayFilter();
}
@@ -482,31 +489,31 @@
private class ArrayFilter extends Filter {
@Override
protected FilterResults performFiltering(CharSequence prefix) {
- FilterResults results = new FilterResults();
+ final FilterResults results = new FilterResults();
if (mOriginalValues == null) {
synchronized (mLock) {
- mOriginalValues = new ArrayList<T>(mObjects);
+ mOriginalValues = new ArrayList<>(mObjects);
}
}
if (prefix == null || prefix.length() == 0) {
- ArrayList<T> list;
+ final ArrayList<T> list;
synchronized (mLock) {
- list = new ArrayList<T>(mOriginalValues);
+ list = new ArrayList<>(mOriginalValues);
}
results.values = list;
results.count = list.size();
} else {
- String prefixString = prefix.toString().toLowerCase();
+ final String prefixString = prefix.toString().toLowerCase();
- ArrayList<T> values;
+ final ArrayList<T> values;
synchronized (mLock) {
- values = new ArrayList<T>(mOriginalValues);
+ values = new ArrayList<>(mOriginalValues);
}
final int count = values.size();
- final ArrayList<T> newValues = new ArrayList<T>();
+ final ArrayList<T> newValues = new ArrayList<>();
for (int i = 0; i < count; i++) {
final T value = values.get(i);
@@ -517,11 +524,8 @@
newValues.add(value);
} else {
final String[] words = valueText.split(" ");
- final int wordCount = words.length;
-
- // Start at index 0, in case valueText starts with space(s)
- for (int k = 0; k < wordCount; k++) {
- if (words[k].startsWith(prefixString)) {
+ for (String word : words) {
+ if (word.startsWith(prefixString)) {
newValues.add(value);
break;
}
diff --git a/core/java/android/widget/AutoCompleteTextView.java b/core/java/android/widget/AutoCompleteTextView.java
index 7d57cb8..6a4e36a 100644
--- a/core/java/android/widget/AutoCompleteTextView.java
+++ b/core/java/android/widget/AutoCompleteTextView.java
@@ -1116,7 +1116,7 @@
protected void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect) {
super.onFocusChanged(focused, direction, previouslyFocusedRect);
- if (mTemporaryDetach) {
+ if (isTemporarilyDetached()) {
// If we are temporarily in the detach state, then do nothing.
return;
}
diff --git a/core/java/android/widget/DatePicker.java b/core/java/android/widget/DatePicker.java
index 6e3dbd8..e3357a7 100644
--- a/core/java/android/widget/DatePicker.java
+++ b/core/java/android/widget/DatePicker.java
@@ -75,8 +75,6 @@
*/
@Widget
public class DatePicker extends FrameLayout {
- private static final String LOG_TAG = DatePicker.class.getSimpleName();
-
private static final int MODE_SPINNER = 1;
private static final int MODE_CALENDAR = 2;
diff --git a/core/java/android/widget/DatePickerCalendarDelegate.java b/core/java/android/widget/DatePickerCalendarDelegate.java
index 5adac01..332e89c 100755
--- a/core/java/android/widget/DatePickerCalendarDelegate.java
+++ b/core/java/android/widget/DatePickerCalendarDelegate.java
@@ -378,9 +378,9 @@
mCurrentDate.set(Calendar.MONTH, monthOfYear);
mCurrentDate.set(Calendar.DAY_OF_MONTH, dayOfMonth);
- mDateChangedListener = callBack;
-
onDateChanged(false, false);
+
+ mDateChangedListener = callBack;
}
@Override
diff --git a/core/java/android/widget/DatePickerSpinnerDelegate.java b/core/java/android/widget/DatePickerSpinnerDelegate.java
index 255de79..d8a3c56 100644
--- a/core/java/android/widget/DatePickerSpinnerDelegate.java
+++ b/core/java/android/widget/DatePickerSpinnerDelegate.java
@@ -244,6 +244,7 @@
setDate(year, monthOfYear, dayOfMonth);
updateSpinners();
updateCalendarView();
+
mOnDateChangedListener = onDateChangedListener;
}
diff --git a/core/java/android/widget/EditText.java b/core/java/android/widget/EditText.java
index 434e3eb..ad35550 100644
--- a/core/java/android/widget/EditText.java
+++ b/core/java/android/widget/EditText.java
@@ -155,6 +155,9 @@
public boolean performAccessibilityActionInternal(int action, Bundle arguments) {
switch (action) {
case AccessibilityNodeInfo.ACTION_SET_TEXT: {
+ if (!isEnabled()) {
+ return false;
+ }
CharSequence text = (arguments != null) ? arguments.getCharSequence(
AccessibilityNodeInfo.ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE) : null;
setText(text);
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index 59d857c..7055f78 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -218,7 +218,6 @@
boolean mShowSoftInputOnFocus = true;
private boolean mPreserveSelection;
private boolean mRestartActionModeOnNextRefresh;
- boolean mTemporaryDetach;
boolean mIsBeingLongClicked;
@@ -367,7 +366,6 @@
showError();
mShowErrorAfterAttach = false;
}
- mTemporaryDetach = false;
final ViewTreeObserver observer = mTextView.getViewTreeObserver();
// No need to create the controller.
@@ -429,7 +427,6 @@
hideCursorAndSpanControllers();
stopTextActionModeWithPreservingSelection();
- mTemporaryDetach = false;
}
private void discardTextDisplayLists() {
@@ -1212,7 +1209,7 @@
stopTextActionModeWithPreservingSelection();
} else {
hideCursorAndSpanControllers();
- if (mTemporaryDetach) {
+ if (mTextView.isTemporarilyDetached()) {
stopTextActionModeWithPreservingSelection();
} else {
stopTextActionMode();
@@ -1866,9 +1863,9 @@
if (hasSelection) {
hideInsertionPointCursorController();
if (mTextActionMode == null) {
- if (mRestartActionModeOnNextRefresh || mTextView.isInExtractedMode()) {
+ if (mRestartActionModeOnNextRefresh) {
// To avoid distraction, newly start action mode only when selection action
- // mode is being restarted or in full screen extracted mode.
+ // mode is being restarted.
startSelectionActionMode();
}
} else if (selectionController == null || !selectionController.isActive()) {
@@ -3640,6 +3637,9 @@
}
if (menu.hasVisibleItems() || mode.getCustomView() != null) {
+ if (mHasSelection && !mTextView.hasTransientState()) {
+ mTextView.setHasTransientState(true);
+ }
return true;
} else {
return false;
@@ -4875,11 +4875,12 @@
@Override
protected int getOffsetAtCoordinate(@NonNull Layout layout, int line, float x) {
- final int primaryOffset = layout.getOffsetForHorizontal(line, x, true);
+ final float localX = mTextView.convertToLocalHorizontalCoordinate(x);
+ final int primaryOffset = layout.getOffsetForHorizontal(line, localX, true);
if (!layout.isLevelBoundary(primaryOffset)) {
return primaryOffset;
}
- final int secondaryOffset = layout.getOffsetForHorizontal(line, x, false);
+ final int secondaryOffset = layout.getOffsetForHorizontal(line, localX, false);
final int currentOffset = getCurrentCursorOffset();
final int primaryDiff = Math.abs(primaryOffset - currentOffset);
final int secondaryDiff = Math.abs(secondaryOffset - currentOffset);
diff --git a/core/java/android/widget/FrameLayout.java b/core/java/android/widget/FrameLayout.java
index fe8916b..9ac4917 100644
--- a/core/java/android/widget/FrameLayout.java
+++ b/core/java/android/widget/FrameLayout.java
@@ -16,17 +16,15 @@
package android.widget;
-import java.util.ArrayList;
+import com.android.internal.R;
+import android.annotation.AttrRes;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.StyleRes;
import android.content.Context;
-import android.content.res.ColorStateList;
import android.content.res.TypedArray;
-import android.graphics.Canvas;
-import android.graphics.PorterDuff;
import android.graphics.Rect;
-import android.graphics.Region;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.Gravity;
@@ -36,8 +34,7 @@
import android.view.ViewHierarchyEncoder;
import android.widget.RemoteViews.RemoteView;
-import com.android.internal.R;
-
+import java.util.ArrayList;
/**
* FrameLayout is designed to block out an area on the screen to display
@@ -75,31 +72,29 @@
@ViewDebug.ExportedProperty(category = "padding")
private int mForegroundPaddingBottom = 0;
- private final Rect mSelfBounds = new Rect();
- private final Rect mOverlayBounds = new Rect();
-
- private final ArrayList<View> mMatchParentChildren = new ArrayList<View>(1);
-
- public FrameLayout(Context context) {
+ private final ArrayList<View> mMatchParentChildren = new ArrayList<>(1);
+
+ public FrameLayout(@NonNull Context context) {
super(context);
}
-
- public FrameLayout(Context context, @Nullable AttributeSet attrs) {
+
+ public FrameLayout(@NonNull Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
- public FrameLayout(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
+ public FrameLayout(@NonNull Context context, @Nullable AttributeSet attrs,
+ @AttrRes int defStyleAttr) {
this(context, attrs, defStyleAttr, 0);
}
- public FrameLayout(
- Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+ public FrameLayout(@NonNull Context context, @Nullable AttributeSet attrs,
+ @AttrRes int defStyleAttr, @StyleRes int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
final TypedArray a = context.obtainStyledAttributes(
- attrs, com.android.internal.R.styleable.FrameLayout, defStyleAttr, defStyleRes);
-
- if (a.getBoolean(com.android.internal.R.styleable.FrameLayout_measureAllChildren, false)) {
+ attrs, R.styleable.FrameLayout, defStyleAttr, defStyleRes);
+
+ if (a.getBoolean(R.styleable.FrameLayout_measureAllChildren, false)) {
setMeasureAllChildren(true);
}
@@ -171,10 +166,6 @@
mPaddingBottom + mForegroundPaddingBottom;
}
-
- /**
- * {@inheritDoc}
- */
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int count = getChildCount();
@@ -264,17 +255,13 @@
}
}
}
-
- /**
- * {@inheritDoc}
- */
+
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
layoutChildren(left, top, right, bottom, false /* no force left gravity */);
}
- void layoutChildren(int left, int top, int right, int bottom,
- boolean forceLeftGravity) {
+ void layoutChildren(int left, int top, int right, int bottom, boolean forceLeftGravity) {
final int count = getChildCount();
final int parentLeft = getPaddingLeftWithForeground();
@@ -378,12 +365,9 @@
return mMeasureAllChildren;
}
- /**
- * {@inheritDoc}
- */
@Override
public LayoutParams generateLayoutParams(AttributeSet attrs) {
- return new FrameLayout.LayoutParams(getContext(), attrs);
+ return new FrameLayout.LayoutParams(getContext(), attrs);
}
@Override
@@ -391,9 +375,6 @@
return false;
}
- /**
- * {@inheritDoc}
- */
@Override
protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
return p instanceof LayoutParams;
@@ -431,34 +412,30 @@
* Per-child layout information for layouts that support margins.
* See {@link android.R.styleable#FrameLayout_Layout FrameLayout Layout Attributes}
* for a list of all child view attributes that this class supports.
- *
+ *
* @attr ref android.R.styleable#FrameLayout_Layout_layout_gravity
*/
public static class LayoutParams extends MarginLayoutParams {
/**
* The gravity to apply with the View to which these layout parameters
* are associated.
+ * <p>
+ * The default value is {@code Gravity.TOP | Gravity.START}
*
* @see android.view.Gravity
- *
* @attr ref android.R.styleable#FrameLayout_Layout_layout_gravity
*/
- public int gravity = -1;
+ public int gravity = DEFAULT_CHILD_GRAVITY;
- /**
- * {@inheritDoc}
- */
- public LayoutParams(Context c, AttributeSet attrs) {
+ public LayoutParams(@NonNull Context c, @Nullable AttributeSet attrs) {
super(c, attrs);
- TypedArray a = c.obtainStyledAttributes(attrs, com.android.internal.R.styleable.FrameLayout_Layout);
- gravity = a.getInt(com.android.internal.R.styleable.FrameLayout_Layout_layout_gravity, -1);
+ final TypedArray a = c.obtainStyledAttributes(attrs, R.styleable.FrameLayout_Layout);
+ gravity = a.getInt(R.styleable.FrameLayout_Layout_layout_gravity,
+ DEFAULT_CHILD_GRAVITY);
a.recycle();
}
- /**
- * {@inheritDoc}
- */
public LayoutParams(int width, int height) {
super(width, height);
}
@@ -468,9 +445,9 @@
* and weight.
*
* @param width the width, either {@link #MATCH_PARENT},
- * {@link #WRAP_CONTENT} or a fixed size in pixels
+ * {@link #WRAP_CONTENT} or a fixed size in pixels
* @param height the height, either {@link #MATCH_PARENT},
- * {@link #WRAP_CONTENT} or a fixed size in pixels
+ * {@link #WRAP_CONTENT} or a fixed size in pixels
* @param gravity the gravity
*
* @see android.view.Gravity
@@ -480,17 +457,11 @@
this.gravity = gravity;
}
- /**
- * {@inheritDoc}
- */
- public LayoutParams(ViewGroup.LayoutParams source) {
+ public LayoutParams(@NonNull ViewGroup.LayoutParams source) {
super(source);
}
- /**
- * {@inheritDoc}
- */
- public LayoutParams(ViewGroup.MarginLayoutParams source) {
+ public LayoutParams(@NonNull ViewGroup.MarginLayoutParams source) {
super(source);
}
@@ -500,7 +471,7 @@
*
* @param source The layout params to copy from.
*/
- public LayoutParams(LayoutParams source) {
+ public LayoutParams(@NonNull LayoutParams source) {
super(source);
this.gravity = source.gravity;
diff --git a/core/java/android/widget/HorizontalScrollView.java b/core/java/android/widget/HorizontalScrollView.java
index f16fdd6..00f368e 100644
--- a/core/java/android/widget/HorizontalScrollView.java
+++ b/core/java/android/widget/HorizontalScrollView.java
@@ -325,16 +325,24 @@
if (getChildCount() > 0) {
final View child = getChildAt(0);
- int width = getMeasuredWidth();
- if (child.getMeasuredWidth() < width) {
- final FrameLayout.LayoutParams lp = (LayoutParams) child.getLayoutParams();
+ final int widthPadding;
+ final int heightPadding;
+ final FrameLayout.LayoutParams lp = (LayoutParams) child.getLayoutParams();
+ final int targetSdkVersion = getContext().getApplicationInfo().targetSdkVersion;
+ if (targetSdkVersion >= Build.VERSION_CODES.M) {
+ widthPadding = mPaddingLeft + mPaddingRight + lp.leftMargin + lp.rightMargin;
+ heightPadding = mPaddingTop + mPaddingBottom + lp.topMargin + lp.bottomMargin;
+ } else {
+ widthPadding = mPaddingLeft + mPaddingRight;
+ heightPadding = mPaddingTop + mPaddingBottom;
+ }
- int childHeightMeasureSpec = getChildMeasureSpec(heightMeasureSpec, mPaddingTop
- + mPaddingBottom, lp.height);
- width -= mPaddingLeft;
- width -= mPaddingRight;
- int childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY);
-
+ int desiredWidth = getMeasuredWidth() - widthPadding;
+ if (child.getMeasuredWidth() < desiredWidth) {
+ final int childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(
+ desiredWidth, MeasureSpec.EXACTLY);
+ final int childHeightMeasureSpec = getChildMeasureSpec(
+ heightMeasureSpec, heightPadding, lp.height);
child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
}
}
@@ -1235,17 +1243,17 @@
}
@Override
- protected void measureChild(View child, int parentWidthMeasureSpec, int parentHeightMeasureSpec) {
+ protected void measureChild(View child, int parentWidthMeasureSpec,
+ int parentHeightMeasureSpec) {
ViewGroup.LayoutParams lp = child.getLayoutParams();
- int childWidthMeasureSpec;
- int childHeightMeasureSpec;
+ final int horizontalPadding = mPaddingLeft + mPaddingRight;
+ final int childWidthMeasureSpec = MeasureSpec.makeSafeMeasureSpec(
+ Math.max(0, MeasureSpec.getSize(parentWidthMeasureSpec) - horizontalPadding),
+ MeasureSpec.UNSPECIFIED);
- childHeightMeasureSpec = getChildMeasureSpec(parentHeightMeasureSpec, mPaddingTop
- + mPaddingBottom, lp.height);
-
- childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
-
+ final int childHeightMeasureSpec = getChildMeasureSpec(parentHeightMeasureSpec,
+ mPaddingTop + mPaddingBottom, lp.height);
child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
}
@@ -1257,8 +1265,11 @@
final int childHeightMeasureSpec = getChildMeasureSpec(parentHeightMeasureSpec,
mPaddingTop + mPaddingBottom + lp.topMargin + lp.bottomMargin
+ heightUsed, lp.height);
- final int childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(
- lp.leftMargin + lp.rightMargin, MeasureSpec.UNSPECIFIED);
+ final int usedTotal = mPaddingLeft + mPaddingRight + lp.leftMargin + lp.rightMargin +
+ widthUsed;
+ final int childWidthMeasureSpec = MeasureSpec.makeSafeMeasureSpec(
+ Math.max(0, MeasureSpec.getSize(parentWidthMeasureSpec) - usedTotal),
+ MeasureSpec.UNSPECIFIED);
child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
}
diff --git a/core/java/android/widget/ImageView.java b/core/java/android/widget/ImageView.java
index 0206577..222a040 100644
--- a/core/java/android/widget/ImageView.java
+++ b/core/java/android/widget/ImageView.java
@@ -911,17 +911,11 @@
}
if (mDrawable != null) {
- // It's possible for this method to be invoked from the constructor before
- // subclass constructors have run. Drawables can and should trigger invalidations
- // and other activity with their callback on visibility changes, which shouldn't
- // happen before subclass constructors finish. However, we won't have set the
- // drawable as visible until the view becomes attached. This guard below keeps
- // multiple calls to this method from constructors from causing issues.
- if (mDrawable.isVisible()) {
- mDrawable.setVisible(false, false);
- }
mDrawable.setCallback(null);
unscheduleDrawable(mDrawable);
+ if (isAttachedToWindow()) {
+ mDrawable.setVisible(false, false);
+ }
}
mDrawable = d;
diff --git a/core/java/android/widget/ListView.java b/core/java/android/widget/ListView.java
index 5b4a368..bfc87f2 100644
--- a/core/java/android/widget/ListView.java
+++ b/core/java/android/widget/ListView.java
@@ -16,15 +16,14 @@
package android.widget;
-import android.annotation.Nullable;
-import android.os.Bundle;
-import android.os.Trace;
+import com.google.android.collect.Lists;
+
import com.android.internal.R;
import com.android.internal.util.Predicate;
-import com.google.android.collect.Lists;
import android.annotation.IdRes;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.content.Context;
import android.content.Intent;
import android.content.res.TypedArray;
@@ -33,6 +32,8 @@
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
+import android.os.Bundle;
+import android.os.Trace;
import android.util.AttributeSet;
import android.util.MathUtils;
import android.util.SparseBooleanArray;
@@ -1106,20 +1107,63 @@
}
private class FocusSelector implements Runnable {
+ // the selector is waiting to set selection on the list view
+ private static final int STATE_SET_SELECTION = 1;
+ // the selector set the selection on the list view, waiting for a layoutChildren pass
+ private static final int STATE_WAIT_FOR_LAYOUT = 2;
+ // the selector's selection has been honored and it is waiting to request focus on the
+ // target child.
+ private static final int STATE_REQUEST_FOCUS = 3;
+
+ private int mAction;
private int mPosition;
private int mPositionTop;
-
- public FocusSelector setup(int position, int top) {
+
+ FocusSelector setupForSetSelection(int position, int top) {
mPosition = position;
mPositionTop = top;
+ mAction = STATE_SET_SELECTION;
return this;
}
-
+
public void run() {
- setSelectionFromTop(mPosition, mPositionTop);
+ if (mAction == STATE_SET_SELECTION) {
+ setSelectionFromTop(mPosition, mPositionTop);
+ mAction = STATE_WAIT_FOR_LAYOUT;
+ } else if (mAction == STATE_REQUEST_FOCUS) {
+ final int childIndex = mPosition - mFirstPosition;
+ final View child = getChildAt(childIndex);
+ if (child != null) {
+ child.requestFocus();
+ }
+ mAction = -1;
+ }
+ }
+
+ @Nullable Runnable setupFocusIfValid(int position) {
+ if (mAction != STATE_WAIT_FOR_LAYOUT || position != mPosition) {
+ return null;
+ }
+ mAction = STATE_REQUEST_FOCUS;
+ return this;
+ }
+
+ void onLayoutComplete() {
+ if (mAction == STATE_WAIT_FOR_LAYOUT) {
+ mAction = -1;
+ }
}
}
-
+
+ @Override
+ protected void onDetachedFromWindow() {
+ if (mFocusSelector != null) {
+ removeCallbacks(mFocusSelector);
+ mFocusSelector = null;
+ }
+ super.onDetachedFromWindow();
+ }
+
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
if (getChildCount() > 0) {
@@ -1132,7 +1176,7 @@
if (mFocusSelector == null) {
mFocusSelector = new FocusSelector();
}
- post(mFocusSelector.setup(childPosition, top));
+ post(mFocusSelector.setupForSetSelection(childPosition, top));
}
}
super.onSizeChanged(w, h, oldw, oldh);
@@ -1629,7 +1673,7 @@
focusLayoutRestoreView = findFocus();
if (focusLayoutRestoreView != null) {
// Tell it we are going to mess with it.
- focusLayoutRestoreView.onStartTemporaryDetach();
+ focusLayoutRestoreView.dispatchStartTemporaryDetach();
}
}
requestFocus();
@@ -1672,7 +1716,21 @@
adjustViewsUpOrDown();
break;
case LAYOUT_SPECIFIC:
- sel = fillSpecific(reconcileSelectedPosition(), mSpecificTop);
+ final int selectedPosition = reconcileSelectedPosition();
+ sel = fillSpecific(selectedPosition, mSpecificTop);
+ /**
+ * When ListView is resized, FocusSelector requests an async selection for the
+ * previously focused item to make sure it is still visible. If the item is not
+ * selectable, it won't regain focus so instead we call FocusSelector
+ * to directly request focus on the view after it is visible.
+ */
+ if (sel == null && mFocusSelector != null) {
+ final Runnable focusRunnable = mFocusSelector
+ .setupFocusIfValid(selectedPosition);
+ if (focusRunnable != null) {
+ post(focusRunnable);
+ }
+ }
break;
case LAYOUT_MOVE_SELECTION:
sel = moveSelection(oldSel, newSel, delta, childrenTop, childrenBottom);
@@ -1792,7 +1850,7 @@
// our view hierarchy.
if (focusLayoutRestoreView != null
&& focusLayoutRestoreView.getWindowToken() != null) {
- focusLayoutRestoreView.onFinishTemporaryDetach();
+ focusLayoutRestoreView.dispatchFinishTemporaryDetach();
}
mLayoutMode = LAYOUT_NORMAL;
@@ -1812,6 +1870,9 @@
invokeOnItemScrollListener();
} finally {
+ if (mFocusSelector != null) {
+ mFocusSelector.onLayoutComplete();
+ }
if (!blockLayoutRequests) {
mBlockLayoutRequests = false;
}
diff --git a/core/java/android/widget/PopupWindow.java b/core/java/android/widget/PopupWindow.java
index 18687c9..0d8d8ed 100644
--- a/core/java/android/widget/PopupWindow.java
+++ b/core/java/android/widget/PopupWindow.java
@@ -173,9 +173,6 @@
private int mHeight = LayoutParams.WRAP_CONTENT;
private int mLastHeight;
- private int mPopupWidth;
- private int mPopupHeight;
-
private float mElevation;
private Drawable mBackground;
@@ -1217,6 +1214,7 @@
final boolean aboveAnchor = findDropDownPosition(anchor, p, xoff, yoff,
p.width, p.height, gravity);
updateAboveAnchor(aboveAnchor);
+ p.accessibilityIdOfAnchor = (anchor != null) ? anchor.getAccessibilityViewId() : -1;
invokePopup(p);
}
@@ -1298,8 +1296,6 @@
mPopupViewInitialLayoutDirectionInherited =
(mContentView.getRawLayoutDirection() == View.LAYOUT_DIRECTION_INHERIT);
- mPopupWidth = p.width;
- mPopupHeight = p.height;
}
/**
@@ -1499,7 +1495,7 @@
*
* @param anchor the view on which the popup window must be anchored
* @param outParams the layout parameters used to display the drop down
- * @param xOffset absolute horizontal offset from the top of the anchor
+ * @param xOffset absolute horizontal offset from the left of the anchor
* @param yOffset absolute vertical offset from the top of the anchor
* @param gravity horizontal gravity specifying popup alignment
* @return true if the popup is translated upwards to fit on screen
@@ -1528,6 +1524,8 @@
// Let the window manager know to align the top to y.
outParams.gravity = Gravity.LEFT | Gravity.TOP;
+ outParams.width = width;
+ outParams.height = height;
final int[] screenLocation = mTmpScreenLocation;
anchor.getLocationOnScreen(screenLocation);
@@ -1535,100 +1533,154 @@
final Rect displayFrame = new Rect();
anchor.getWindowVisibleDisplayFrame(displayFrame);
- boolean onTop = false;
+ // First, attempt to fit the popup vertically without resizing.
+ final boolean fitsVertical = tryFitVertical(outParams, yOffset, height,
+ anchorHeight, drawingLocation[1], screenLocation[1], displayFrame.top,
+ displayFrame.bottom, false);
- final View root = anchor.getRootView();
- final int screenY = screenLocation[1] + anchorHeight + yOffset;
- final boolean tooFarDown = screenY + height > displayFrame.bottom;
- final boolean tooFarRight = outParams.x + width > root.getWidth();
- if (tooFarDown || tooFarRight) {
- // If the popup extends beyond the visible area, try to scroll the
- // parent so that it is fully visible.
- if (mAllowScrollingAnchorParent) {
- final int scrollX = anchor.getScrollX();
- final int scrollY = anchor.getScrollY();
- final Rect r = new Rect(scrollX, scrollY, scrollX + width + xOffset,
- scrollY + height + anchorHeight + yOffset);
- anchor.requestRectangleOnScreen(r, true);
- }
+ // Next, attempt to fit the popup horizontally without resizing.
+ final boolean fitsHorizontal = tryFitHorizontal(outParams, xOffset, width,
+ anchorWidth, drawingLocation[0], screenLocation[0], displayFrame.left,
+ displayFrame.right, false);
- // Update for the new anchor position.
- anchor.getLocationInWindow(drawingLocation);
- outParams.x = drawingLocation[0] + xOffset;
- outParams.y = drawingLocation[1] + anchorHeight + yOffset;
+ // If the popup still doesn't fit, attempt to scroll the parent.
+ if (!fitsVertical || !fitsHorizontal) {
+ final int scrollX = anchor.getScrollX();
+ final int scrollY = anchor.getScrollY();
+ final Rect r = new Rect(scrollX, scrollY, scrollX + width + xOffset,
+ scrollY + height + anchorHeight + yOffset);
+ if (mAllowScrollingAnchorParent && anchor.requestRectangleOnScreen(r, true)) {
+ // Reset for the new anchor position.
+ anchor.getLocationInWindow(drawingLocation);
+ outParams.x = drawingLocation[0] + xOffset;
+ outParams.y = drawingLocation[1] + anchorHeight + yOffset;
- // Preserve the gravity adjustment.
- if (hgrav == Gravity.RIGHT) {
- outParams.x -= width - anchorWidth;
- }
-
- final int newScreenY = screenLocation[1] + anchorHeight + yOffset;
- final boolean stillTooFarDown = newScreenY + height > displayFrame.bottom;
- if (stillTooFarDown) {
- // If the popup is still too far down, re-evaluate the space
- // available and decide whether the pop-up will go above or
- // below the anchor.
- anchor.getLocationOnScreen(screenLocation);
-
- final int below = displayFrame.bottom - screenLocation[1] - anchorHeight - yOffset;
- final int above = screenLocation[1] - displayFrame.top + yOffset;
- onTop = above > below;
-
- if (onTop) {
- // Move everything up.
- if (mOverlapAnchor) {
- yOffset += anchorHeight;
- }
- outParams.y = drawingLocation[1] - height + yOffset;
+ // Preserve the gravity adjustment.
+ if (hgrav == Gravity.RIGHT) {
+ outParams.x -= width - anchorWidth;
}
}
+
+ // Try to fit the popup again and allowing resizing.
+ tryFitVertical(outParams, yOffset, height, anchorHeight, drawingLocation[1],
+ screenLocation[1], displayFrame.top, displayFrame.bottom, mClipToScreen);
+ tryFitHorizontal(outParams, xOffset, width, anchorWidth, drawingLocation[0],
+ screenLocation[0], displayFrame.left, displayFrame.right, mClipToScreen);
}
- if (mClipToScreen) {
- // Use screen coordinates for comparison against display frame.
- final int winOffsetX = screenLocation[0] - drawingLocation[0];
- final int winOffsetY = screenLocation[1] - drawingLocation[1];
- outParams.x += winOffsetX;
- outParams.y += winOffsetY;
+ // Return whether the popup's top edge is above the anchor's top edge.
+ return outParams.y < drawingLocation[1];
+ }
- final int right = outParams.x + width;
- if (right > displayFrame.right) {
- // The popup is too far right, move it back in.
- outParams.x -= right - displayFrame.right;
- }
-
- if (outParams.x < displayFrame.left) {
- // The popup is too far left, move it back in and clip if it's
- // still too large.
- outParams.x = displayFrame.left;
-
- final int displayFrameWidth = displayFrame.width();
- width = Math.min(width, displayFrameWidth);
- }
-
- final int bottom = outParams.y + height;
- if (bottom > displayFrame.bottom) {
- // The popup is too far down, move it back in.
- outParams.y -= bottom - displayFrame.bottom;
- }
-
- if (outParams.y < displayFrame.top) {
- // The popup is too far up, move it back in and clip if
- // it's still too large.
- outParams.y = displayFrame.top;
-
- final int displayFrameHeight = displayFrame.height();
- height = Math.min(height, displayFrameHeight);
- }
-
- outParams.x -= winOffsetX;
- outParams.y -= winOffsetY;
+ private boolean tryFitVertical(@NonNull LayoutParams outParams, int yOffset, int height,
+ int anchorHeight, int drawingLocationY, int screenLocationY, int displayFrameTop,
+ int displayFrameBottom, boolean allowResize) {
+ final int anchorTopInScreen = screenLocationY + anchorHeight + yOffset;
+ final int spaceBelow = displayFrameBottom - anchorTopInScreen;
+ if (height <= spaceBelow) {
+ return true;
}
- outParams.width = width;
+ final int spaceAbove = displayFrameTop + anchorTopInScreen - anchorHeight;
+ if (height <= spaceAbove) {
+ // Move everything up.
+ if (mOverlapAnchor) {
+ yOffset += anchorHeight;
+ }
+ outParams.y = drawingLocationY - height + yOffset;
+
+ return true;
+ }
+
+ if (positionInDisplayVertical(outParams, height, drawingLocationY, screenLocationY,
+ displayFrameTop, displayFrameBottom, allowResize)) {
+ return true;
+ }
+
+ return false;
+ }
+
+ private boolean positionInDisplayVertical(@NonNull LayoutParams outParams, int height,
+ int drawingLocationY, int screenLocationY, int displayFrameTop, int displayFrameBottom,
+ boolean canResize) {
+ boolean fitsInDisplay = true;
+
+ final int winOffsetY = screenLocationY - drawingLocationY;
+ outParams.y += winOffsetY;
outParams.height = height;
- return onTop;
+ final int bottom = outParams.y + height;
+ if (bottom > displayFrameBottom) {
+ // The popup is too far down, move it back in.
+ outParams.y -= bottom - displayFrameBottom;
+ }
+
+ if (outParams.y < displayFrameTop) {
+ // The popup is too far up, move it back in and clip if
+ // it's still too large.
+ outParams.y = displayFrameTop;
+
+ final int displayFrameHeight = displayFrameBottom - displayFrameTop;
+ if (canResize && height > displayFrameHeight) {
+ outParams.height = displayFrameHeight;
+ } else {
+ fitsInDisplay = false;
+ }
+ }
+
+ outParams.y -= winOffsetY;
+
+ return fitsInDisplay;
+ }
+
+ private boolean tryFitHorizontal(@NonNull LayoutParams outParams, int xOffset, int width,
+ int anchorWidth, int drawingLocationX, int screenLocationX, int displayFrameLeft,
+ int displayFrameRight, boolean allowResize) {
+ final int anchorLeftInScreen = screenLocationX + xOffset;
+ final int spaceRight = displayFrameRight - anchorLeftInScreen;
+ if (width <= spaceRight) {
+ return true;
+ }
+
+ if (positionInDisplayHorizontal(outParams, width, drawingLocationX, screenLocationX,
+ displayFrameLeft, displayFrameRight, allowResize)) {
+ return true;
+ }
+
+ return false;
+ }
+
+ private boolean positionInDisplayHorizontal(@NonNull LayoutParams outParams, int width,
+ int drawingLocationX, int screenLocationX, int displayFrameLeft, int displayFrameRight,
+ boolean canResize) {
+ boolean fitsInDisplay = true;
+
+ // Use screen coordinates for comparison against display frame.
+ final int winOffsetX = screenLocationX - drawingLocationX;
+ outParams.x += winOffsetX;
+
+ final int right = outParams.x + width;
+ if (right > displayFrameRight) {
+ // The popup is too far right, move it back in.
+ outParams.x -= right - displayFrameRight;
+ }
+
+ if (outParams.x < displayFrameLeft) {
+ // The popup is too far left, move it back in and clip if it's
+ // still too large.
+ outParams.x = displayFrameLeft;
+
+ final int displayFrameWidth = displayFrameRight - displayFrameLeft;
+ if (canResize && width > displayFrameWidth) {
+ outParams.width = displayFrameWidth;
+ } else {
+ fitsInDisplay = false;
+ }
+ }
+
+ outParams.x -= winOffsetX;
+
+ return fitsInDisplay;
}
/**
@@ -1989,6 +2041,13 @@
update = true;
}
+ int newAccessibilityIdOfAnchor =
+ (mAnchor != null) ? mAnchor.get().getAccessibilityViewId() : -1;
+ if (newAccessibilityIdOfAnchor != p.accessibilityIdOfAnchor) {
+ p.accessibilityIdOfAnchor = newAccessibilityIdOfAnchor;
+ update = true;
+ }
+
if (update) {
setLayoutDirectionFromAnchor();
mWindowManager.updateViewLayout(mDecorView, p);
@@ -2006,7 +2065,7 @@
* @param height the new height, must be >= 0 or -1 to ignore
*/
public void update(View anchor, int width, int height) {
- update(anchor, false, 0, 0, true, width, height);
+ update(anchor, false, 0, 0, width, height);
}
/**
@@ -2026,11 +2085,11 @@
* @param height the new height, 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, true, width, height);
+ update(anchor, true, xoff, yoff, width, height);
}
private void update(View anchor, boolean updateLocation, int xoff, int yoff,
- boolean updateDimension, int width, int height) {
+ int width, int height) {
if (!isShowing() || mContentView == null) {
return;
@@ -2055,13 +2114,13 @@
final int oldX = p.x;
final int oldY = p.y;
- if (updateDimension) {
- if (width == -1) {
- width = mPopupWidth;
- }
- if (height == -1) {
- height = mPopupHeight;
- }
+ // If an explicit width/height has not specified, use the most recent
+ // explicitly specified value (either from setWidth/Height or update).
+ if (width == -1) {
+ width = mWidth;
+ }
+ if (height == -1) {
+ height = mHeight;
}
final boolean aboveAnchor = findDropDownPosition(anchor, p, mAnchorXoff, mAnchorYoff,
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java
index 8bd63df..6d2cea6 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -17,6 +17,7 @@
package android.widget;
import android.annotation.ColorInt;
+import android.app.ActivityManager.StackId;
import android.app.ActivityOptions;
import android.app.ActivityThread;
import android.app.Application;
@@ -228,6 +229,11 @@
public boolean onClickHandler(View view, PendingIntent pendingIntent,
Intent fillInIntent) {
+ return onClickHandler(view, pendingIntent, fillInIntent, StackId.INVALID_STACK_ID);
+ }
+
+ public boolean onClickHandler(View view, PendingIntent pendingIntent,
+ Intent fillInIntent, int launchStackId) {
try {
// TODO: Unregister this handler if PendingIntent.FLAG_ONE_SHOT?
Context context = view.getContext();
@@ -239,6 +245,10 @@
0, 0,
view.getMeasuredWidth(), view.getMeasuredHeight());
}
+
+ if (launchStackId != StackId.INVALID_STACK_ID) {
+ opts.setLaunchStackId(launchStackId);
+ }
context.startIntentSender(
pendingIntent.getIntentSender(), fillInIntent,
Intent.FLAG_ACTIVITY_NEW_TASK,
diff --git a/core/java/android/widget/ScrollView.java b/core/java/android/widget/ScrollView.java
index 3f7a07b..0555cd4 100644
--- a/core/java/android/widget/ScrollView.java
+++ b/core/java/android/widget/ScrollView.java
@@ -350,24 +350,24 @@
if (getChildCount() > 0) {
final View child = getChildAt(0);
- final int height = getMeasuredHeight();
- if (child.getMeasuredHeight() < height) {
- final int widthPadding;
- final int heightPadding;
- final FrameLayout.LayoutParams lp = (LayoutParams) child.getLayoutParams();
- final int targetSdkVersion = getContext().getApplicationInfo().targetSdkVersion;
- if (targetSdkVersion >= VERSION_CODES.M) {
- widthPadding = mPaddingLeft + mPaddingRight + lp.leftMargin + lp.rightMargin;
- heightPadding = mPaddingTop + mPaddingBottom + lp.topMargin + lp.bottomMargin;
- } else {
- widthPadding = mPaddingLeft + mPaddingRight;
- heightPadding = mPaddingTop + mPaddingBottom;
- }
+ final int widthPadding;
+ final int heightPadding;
+ final int targetSdkVersion = getContext().getApplicationInfo().targetSdkVersion;
+ final FrameLayout.LayoutParams lp = (LayoutParams) child.getLayoutParams();
+ if (targetSdkVersion >= VERSION_CODES.M) {
+ widthPadding = mPaddingLeft + mPaddingRight + lp.leftMargin + lp.rightMargin;
+ heightPadding = mPaddingTop + mPaddingBottom + lp.topMargin + lp.bottomMargin;
+ } else {
+ widthPadding = mPaddingLeft + mPaddingRight;
+ heightPadding = mPaddingTop + mPaddingBottom;
+ }
+ final int desiredHeight = getMeasuredHeight() - heightPadding;
+ if (child.getMeasuredHeight() < desiredHeight) {
final int childWidthMeasureSpec = getChildMeasureSpec(
widthMeasureSpec, widthPadding, lp.width);
final int childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(
- height - heightPadding, MeasureSpec.EXACTLY);
+ desiredHeight, MeasureSpec.EXACTLY);
child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
}
}
@@ -1268,9 +1268,10 @@
childWidthMeasureSpec = getChildMeasureSpec(parentWidthMeasureSpec, mPaddingLeft
+ mPaddingRight, lp.width);
-
+ final int verticalPadding = mPaddingTop + mPaddingBottom;
childHeightMeasureSpec = MeasureSpec.makeSafeMeasureSpec(
- MeasureSpec.getSize(parentHeightMeasureSpec), MeasureSpec.UNSPECIFIED);
+ Math.max(0, MeasureSpec.getSize(parentHeightMeasureSpec) - verticalPadding),
+ MeasureSpec.UNSPECIFIED);
child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
}
@@ -1283,8 +1284,11 @@
final int childWidthMeasureSpec = getChildMeasureSpec(parentWidthMeasureSpec,
mPaddingLeft + mPaddingRight + lp.leftMargin + lp.rightMargin
+ widthUsed, lp.width);
+ final int usedTotal = mPaddingTop + mPaddingBottom + lp.topMargin + lp.bottomMargin +
+ heightUsed;
final int childHeightMeasureSpec = MeasureSpec.makeSafeMeasureSpec(
- MeasureSpec.getSize(parentHeightMeasureSpec), MeasureSpec.UNSPECIFIED);
+ Math.max(0, MeasureSpec.getSize(parentHeightMeasureSpec) - usedTotal),
+ MeasureSpec.UNSPECIFIED);
child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
}
diff --git a/core/java/android/widget/SimpleMonthView.java b/core/java/android/widget/SimpleMonthView.java
index 43cf5a1..ee716df 100644
--- a/core/java/android/widget/SimpleMonthView.java
+++ b/core/java/android/widget/SimpleMonthView.java
@@ -16,6 +16,9 @@
package android.widget;
+import com.android.internal.R;
+import com.android.internal.widget.ExploreByTouchHelper;
+
import android.annotation.Nullable;
import android.content.Context;
import android.content.res.ColorStateList;
@@ -44,14 +47,13 @@
import android.view.accessibility.AccessibilityNodeInfo;
import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
-import com.android.internal.R;
-import com.android.internal.widget.ExploreByTouchHelper;
-
import java.text.NumberFormat;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Locale;
+import libcore.icu.LocaleData;
+
/**
* A calendar-like view displaying a specified month and the appropriate selectable day numbers
* within the specified month.
@@ -66,7 +68,6 @@
private static final int DEFAULT_WEEK_START = Calendar.SUNDAY;
private static final String MONTH_YEAR_FORMAT = "MMMMy";
- private static final String DAY_OF_WEEK_FORMAT = "EEEEE";
private static final int SELECTED_HIGHLIGHT_ALPHA = 0xB0;
@@ -80,6 +81,7 @@
private final Paint mDayHighlightPaint = new Paint();
private final Paint mDayHighlightSelectorPaint = new Paint();
+ /** Array of single-character weekday labels ordered by column index. */
private final String[] mDayOfWeekLabels = new String[7];
private final Calendar mCalendar;
@@ -120,7 +122,7 @@
*/
private int mToday = DEFAULT_SELECTED_DAY;
- /** The first day of the week (ex. Calendar.SUNDAY). */
+ /** The first day of the week (ex. Calendar.SUNDAY) indexed from one. */
private int mWeekStart = DEFAULT_WEEK_START;
/** The number of days (ex. 28) in the current month. */
@@ -199,13 +201,11 @@
Log.d(LOG_TAG, "mWeekStart => " + mWeekStart);
}
- final Calendar calendar = Calendar.getInstance(mLocale);
- calendar.setFirstDayOfWeek(mWeekStart);
-
- final SimpleDateFormat formatter = new SimpleDateFormat(DAY_OF_WEEK_FORMAT, mLocale);
- for (int i = 0; i < 7; i++) {
- calendar.set(Calendar.DAY_OF_WEEK, i);
- mDayOfWeekLabels[i] = formatter.format(calendar.getTime());
+ // Use tiny (e.g. single-character) weekday names from ICU. The indices
+ // for this list correspond to Calendar days, e.g. SUNDAY is index 1.
+ final String[] tinyWeekdayNames = LocaleData.get(mLocale).tinyWeekdayNames;
+ for (int i = 0; i < DAYS_IN_WEEK; i++) {
+ mDayOfWeekLabels[i] = tinyWeekdayNames[(mWeekStart + i - 1) % DAYS_IN_WEEK + 1];
}
if (DEBUG_WRONG_DATE) {
@@ -662,8 +662,7 @@
colCenterRtl = colCenter;
}
- final int dayOfWeek = (col + mWeekStart) % DAYS_IN_WEEK;
- final String label = mDayOfWeekLabels[dayOfWeek];
+ final String label = mDayOfWeekLabels[col];
canvas.drawText(label, colCenterRtl, rowCenter - halfLineHeight, p);
}
}
@@ -813,6 +812,11 @@
*/
void setMonthParams(int selectedDay, int month, int year, int weekStart, int enabledDayStart,
int enabledDayEnd) {
+ if (DEBUG_WRONG_DATE) {
+ Log.d(LOG_TAG, "setMonthParams(" + selectedDay + ", " + month + ", " + year + ", "
+ + weekStart + ", " + enabledDayStart + ", " + enabledDayEnd + ")");
+ }
+
mActivatedDay = selectedDay;
if (isValidMonth(month)) {
@@ -849,6 +853,14 @@
mTouchHelper.invalidateRoot();
updateMonthYearLabel();
+
+ if (DEBUG_WRONG_DATE) {
+ Log.d(LOG_TAG, "mMonth = " + mMonth);
+ Log.d(LOG_TAG, "mDayOfWeekStart = " + mDayOfWeekStart);
+ Log.d(LOG_TAG, "mWeekStart = " + mWeekStart);
+ Log.d(LOG_TAG, "mDaysInMonth = " + mDaysInMonth);
+ Log.d(LOG_TAG, "mToday = " + mToday);
+ }
}
private static int getDaysInMonth(int month, int year) {
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 3195097..3b7b16d 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -17,6 +17,7 @@
package android.widget;
import static android.os.Build.VERSION_CODES.JELLY_BEAN_MR1;
+
import android.R;
import android.annotation.ColorInt;
import android.annotation.DrawableRes;
@@ -329,10 +330,6 @@
private int mCurTextColor;
private int mCurHintTextColor;
private boolean mFreezesText;
- private boolean mDispatchTemporaryDetach;
-
- /** Whether this view is temporarily detached from the parent view. */
- boolean mTemporaryDetach;
private Editable.Factory mEditableFactory = Editable.Factory.getInstance();
private Spannable.Factory mSpannableFactory = Spannable.Factory.getInstance();
@@ -2892,6 +2889,11 @@
public void setTextLocale(@NonNull Locale locale) {
mLocalesChanged = true;
mTextPaint.setTextLocale(locale);
+ if (mLayout != null) {
+ nullLayouts();
+ requestLayout();
+ invalidate();
+ }
}
/**
@@ -2908,6 +2910,11 @@
public void setTextLocales(@NonNull @Size(min=1) LocaleList locales) {
mLocalesChanged = true;
mTextPaint.setTextLocales(locales);
+ if (mLayout != null) {
+ nullLayouts();
+ requestLayout();
+ invalidate();
+ }
}
@Override
@@ -2915,6 +2922,11 @@
super.onConfigurationChanged(newConfig);
if (!mLocalesChanged) {
mTextPaint.setTextLocales(LocaleList.getDefault());
+ if (mLayout != null) {
+ nullLayouts();
+ requestLayout();
+ invalidate();
+ }
}
}
@@ -3115,10 +3127,15 @@
}
/**
+ * Returns the font feature settings. The format is the same as the CSS
+ * font-feature-settings attribute:
+ * <a href="http://dev.w3.org/csswg/css-fonts/#propdef-font-feature-settings">
+ * http://dev.w3.org/csswg/css-fonts/#propdef-font-feature-settings</a>
+ *
* @return the currently set font feature settings. Default is null.
*
* @see #setFontFeatureSettings(String)
- * @see Paint#setFontFeatureSettings
+ * @see Paint#setFontFeatureSettings(String) Paint.setFontFeatureSettings(String)
*/
@Nullable
public String getFontFeatureSettings() {
@@ -3182,13 +3199,15 @@
}
/**
- * Sets font feature settings. The format is the same as the CSS
+ * Sets font feature settings. The format is the same as the CSS
* font-feature-settings attribute:
- * http://dev.w3.org/csswg/css-fonts/#propdef-font-feature-settings
+ * <a href="http://dev.w3.org/csswg/css-fonts/#propdef-font-feature-settings">
+ * http://dev.w3.org/csswg/css-fonts/#propdef-font-feature-settings</a>
*
* @param fontFeatureSettings font feature settings represented as CSS compatible string
+ *
* @see #getFontFeatureSettings()
- * @see Paint#getFontFeatureSettings
+ * @see Paint#getFontFeatureSettings() Paint.getFontFeatureSettings()
*
* @attr ref android.R.styleable#TextView_fontFeatureSettings
*/
@@ -3403,17 +3422,10 @@
}
/**
- * Sets whether the movement method will automatically be set to {@link LinkMovementMethod}
- * after {@link #setText} or {@link #append} is called. The movement method is set if one of the
- * following is true:
- * <ul>
- * <li>{@link #setAutoLinkMask} has been set to nonzero and links are detected in
- * {@link #setText} or {@link #append}.
- * <li>The input for {@link #setText} or {@link #append} contains a {@link ClickableSpan}.
- * </ul>
- *
- * <p>This function does not have an immediate effect, movement method will be set only after a
- * call to {@link #setText} or {@link #append}. The default is true.</p>
+ * Sets whether the movement method will automatically be set to
+ * {@link LinkMovementMethod} if {@link #setAutoLinkMask} has been
+ * set to nonzero and links are detected in {@link #setText}.
+ * The default is true.
*
* @attr ref android.R.styleable#TextView_linksClickable
*/
@@ -3423,14 +3435,10 @@
}
/**
- * Returns whether the movement method will automatically be set to {@link LinkMovementMethod}
- * after {@link #setText} or {@link #append} is called.
- *
- * See {@link #setLinksClickable} for details.
- *
- * <p>The default is true.</p>
- *
- * @see #setLinksClickable
+ * Returns whether the movement method will automatically be set to
+ * {@link LinkMovementMethod} if {@link #setAutoLinkMask} has been
+ * set to nonzero and links are detected in {@link #setText}.
+ * The default is true.
*
* @attr ref android.R.styleable#TextView_linksClickable
*/
@@ -4024,19 +4032,13 @@
((Editable) mText).append(text, start, end);
- boolean hasClickableSpans = false;
if (mAutoLinkMask != 0) {
- hasClickableSpans = Linkify.addLinks((Spannable) mText, mAutoLinkMask);
- } else if (mLinksClickable && text instanceof Spanned) {
- ClickableSpan[] clickableSpans =
- ((Spanned) text).getSpans(0, text.length(), ClickableSpan.class);
- hasClickableSpans = clickableSpans != null && clickableSpans.length > 0;
- }
-
- // Do not change the movement method for text that supports text selection as it
- // would prevent an arbitrary cursor displacement.
- if (hasClickableSpans && mLinksClickable && !textCanBeSelected()) {
- setMovementMethod(LinkMovementMethod.getInstance());
+ boolean linksWereAdded = Linkify.addLinks((Spannable) mText, mAutoLinkMask);
+ // Do not change the movement method for text that support text selection as it
+ // would prevent an arbitrary cursor displacement.
+ if (linksWereAdded && mLinksClickable && !textCanBeSelected()) {
+ setMovementMethod(LinkMovementMethod.getInstance());
+ }
}
}
@@ -4389,7 +4391,6 @@
text = TextUtils.stringOrSpannedString(text);
}
- boolean hasClickableSpans = false;
if (mAutoLinkMask != 0) {
Spannable s2;
@@ -4399,32 +4400,22 @@
s2 = mSpannableFactory.newSpannable(text);
}
- hasClickableSpans = Linkify.addLinks(s2, mAutoLinkMask);
- if (hasClickableSpans) {
+ if (Linkify.addLinks(s2, mAutoLinkMask)) {
text = s2;
- }
- } else if (mLinksClickable && text instanceof Spanned) {
- ClickableSpan[] clickableSpans =
- ((Spanned) text).getSpans(0, text.length(), ClickableSpan.class);
- hasClickableSpans = clickableSpans != null && clickableSpans.length > 0;
- if (hasClickableSpans && !(text instanceof Spannable)) {
- text = mSpannableFactory.newSpannable(text);
- }
- }
+ type = (type == BufferType.EDITABLE) ? BufferType.EDITABLE : BufferType.SPANNABLE;
- if (hasClickableSpans) {
- type = (type == BufferType.EDITABLE) ? BufferType.EDITABLE : BufferType.SPANNABLE;
- /*
- * We must go ahead and set the text before changing the
- * movement method, because setMovementMethod() may call
- * setText() again to try to upgrade the buffer type.
- */
- mText = text;
+ /*
+ * We must go ahead and set the text before changing the
+ * movement method, because setMovementMethod() may call
+ * setText() again to try to upgrade the buffer type.
+ */
+ mText = text;
- // Do not change the movement method for text that supports text selection as it
- // would prevent an arbitrary cursor displacement.
- if (mLinksClickable && !textCanBeSelected()) {
- setMovementMethod(LinkMovementMethod.getInstance());
+ // Do not change the movement method for text that support text selection as it
+ // would prevent an arbitrary cursor displacement.
+ if (mLinksClickable && !textCanBeSelected()) {
+ setMovementMethod(LinkMovementMethod.getInstance());
+ }
}
}
@@ -5411,8 +5402,6 @@
protected void onAttachedToWindow() {
super.onAttachedToWindow();
- mTemporaryDetach = false;
-
if (mEditor != null) mEditor.onAttachedToWindow();
if (mPreDrawListenerDetached) {
@@ -8294,14 +8283,12 @@
newSelEnd = Selection.getSelectionEnd(buf);
}
- if (newSelStart == newSelEnd && hasTransientState()) {
- setHasTransientState(false);
- } else if (newSelStart != newSelEnd && !hasTransientState()) {
- setHasTransientState(true);
- }
-
if (mEditor != null) {
mEditor.refreshTextActionMode();
+ if (!hasSelection() && mEditor.mTextActionMode == null && hasTransientState()) {
+ // User generated selection has been removed.
+ setHasTransientState(false);
+ }
}
onSelectionChanged(newSelStart, newSelEnd);
}
@@ -8373,40 +8360,9 @@
}
}
- /**
- * @hide
- */
- @Override
- public void dispatchFinishTemporaryDetach() {
- mDispatchTemporaryDetach = true;
- super.dispatchFinishTemporaryDetach();
- mDispatchTemporaryDetach = false;
- }
-
- @Override
- public void onStartTemporaryDetach() {
- super.onStartTemporaryDetach();
- // Only track when onStartTemporaryDetach() is called directly,
- // usually because this instance is an editable field in a list
- if (!mDispatchTemporaryDetach) mTemporaryDetach = true;
-
- // Tell the editor that we are temporarily detached. It can use this to preserve
- // selection state as needed.
- if (mEditor != null) mEditor.mTemporaryDetach = true;
- }
-
- @Override
- public void onFinishTemporaryDetach() {
- super.onFinishTemporaryDetach();
- // Only track when onStartTemporaryDetach() is called directly,
- // usually because this instance is an editable field in a list
- if (!mDispatchTemporaryDetach) mTemporaryDetach = false;
- if (mEditor != null) mEditor.mTemporaryDetach = false;
- }
-
@Override
protected void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect) {
- if (mTemporaryDetach) {
+ if (isTemporarilyDetached()) {
// If we are temporarily in the detach state, then do nothing.
super.onFocusChanged(focused, direction, previouslyFocusedRect);
return;
@@ -9101,6 +9057,9 @@
if (mBufferType == BufferType.EDITABLE) {
info.setEditable(true);
+ if (isEnabled()) {
+ info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_SET_TEXT);
+ }
}
if (mEditor != null) {
@@ -9232,6 +9191,17 @@
}
}
} return false;
+ case AccessibilityNodeInfo.ACTION_SET_TEXT: {
+ if (!isEnabled() || (mBufferType != BufferType.EDITABLE)) {
+ return false;
+ }
+ CharSequence text = (arguments != null) ? arguments.getCharSequence(
+ AccessibilityNodeInfo.ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE) : null;
+ setText(text);
+ if (text != null && text.length() > 0) {
+ Selection.setSelection((Spannable) mText, text.length());
+ }
+ } return true;
default: {
return super.performAccessibilityActionInternal(action, arguments);
}
diff --git a/core/java/android/widget/Toolbar.java b/core/java/android/widget/Toolbar.java
index 06daf61..9cdb73a 100644
--- a/core/java/android/widget/Toolbar.java
+++ b/core/java/android/widget/Toolbar.java
@@ -23,6 +23,7 @@
import android.annotation.Nullable;
import android.annotation.StringRes;
import android.annotation.StyleRes;
+import android.annotation.TestApi;
import android.app.ActionBar;
import android.content.Context;
import android.content.res.TypedArray;
@@ -106,6 +107,8 @@
* @attr ref android.R.styleable#Toolbar_contentInsetLeft
* @attr ref android.R.styleable#Toolbar_contentInsetRight
* @attr ref android.R.styleable#Toolbar_contentInsetStart
+ * @attr ref android.R.styleable#Toolbar_contentInsetStartWithNavigation
+ * @attr ref android.R.styleable#Toolbar_contentInsetEndWithActions
* @attr ref android.R.styleable#Toolbar_gravity
* @attr ref android.R.styleable#Toolbar_logo
* @attr ref android.R.styleable#Toolbar_logoDescription
@@ -159,6 +162,8 @@
private int mTitleMarginBottom;
private final RtlSpacingHelper mContentInsets = new RtlSpacingHelper();
+ private int mContentInsetStartWithNavigation;
+ private int mContentInsetEndWithActions;
private int mGravity = Gravity.START | Gravity.CENTER_VERTICAL;
@@ -272,6 +277,11 @@
mContentInsets.setRelative(contentInsetStart, contentInsetEnd);
}
+ mContentInsetStartWithNavigation = a.getDimensionPixelOffset(
+ R.styleable.Toolbar_contentInsetStartWithNavigation, RtlSpacingHelper.UNDEFINED);
+ mContentInsetEndWithActions = a.getDimensionPixelOffset(
+ R.styleable.Toolbar_contentInsetEndWithActions, RtlSpacingHelper.UNDEFINED);
+
mCollapseIcon = a.getDrawable(R.styleable.Toolbar_collapseIcon);
mCollapseDescription = a.getText(R.styleable.Toolbar_collapseContentDescription);
@@ -967,6 +977,15 @@
}
/**
+ * @hide
+ */
+ @Nullable
+ @TestApi
+ public View getNavigationView() {
+ return mNavButtonView;
+ }
+
+ /**
* Return the Menu shown in the toolbar.
*
* <p>Applications that wish to populate the toolbar's menu can do so from here. To use
@@ -1055,7 +1074,7 @@
}
/**
- * Set the content insets for this toolbar relative to layout direction.
+ * Sets the content insets for this toolbar relative to layout direction.
*
* <p>The content inset affects the valid area for Toolbar content other than
* the navigation button and menu. Insets define the minimum margin for these components
@@ -1069,13 +1088,15 @@
* @see #getContentInsetEnd()
* @see #getContentInsetLeft()
* @see #getContentInsetRight()
+ * @attr ref android.R.styleable#Toolbar_contentInsetEnd
+ * @attr ref android.R.styleable#Toolbar_contentInsetStart
*/
public void setContentInsetsRelative(int contentInsetStart, int contentInsetEnd) {
mContentInsets.setRelative(contentInsetStart, contentInsetEnd);
}
/**
- * Get the starting content inset for this toolbar.
+ * Gets the starting content inset for this toolbar.
*
* <p>The content inset affects the valid area for Toolbar content other than
* the navigation button and menu. Insets define the minimum margin for these components
@@ -1088,13 +1109,14 @@
* @see #getContentInsetEnd()
* @see #getContentInsetLeft()
* @see #getContentInsetRight()
+ * @attr ref android.R.styleable#Toolbar_contentInsetStart
*/
public int getContentInsetStart() {
return mContentInsets.getStart();
}
/**
- * Get the ending content inset for this toolbar.
+ * Gets the ending content inset for this toolbar.
*
* <p>The content inset affects the valid area for Toolbar content other than
* the navigation button and menu. Insets define the minimum margin for these components
@@ -1107,13 +1129,14 @@
* @see #getContentInsetStart()
* @see #getContentInsetLeft()
* @see #getContentInsetRight()
+ * @attr ref android.R.styleable#Toolbar_contentInsetEnd
*/
public int getContentInsetEnd() {
return mContentInsets.getEnd();
}
/**
- * Set the content insets for this toolbar.
+ * Sets the content insets for this toolbar.
*
* <p>The content inset affects the valid area for Toolbar content other than
* the navigation button and menu. Insets define the minimum margin for these components
@@ -1127,13 +1150,15 @@
* @see #getContentInsetEnd()
* @see #getContentInsetLeft()
* @see #getContentInsetRight()
+ * @attr ref android.R.styleable#Toolbar_contentInsetLeft
+ * @attr ref android.R.styleable#Toolbar_contentInsetRight
*/
public void setContentInsetsAbsolute(int contentInsetLeft, int contentInsetRight) {
mContentInsets.setAbsolute(contentInsetLeft, contentInsetRight);
}
/**
- * Get the left content inset for this toolbar.
+ * Gets the left content inset for this toolbar.
*
* <p>The content inset affects the valid area for Toolbar content other than
* the navigation button and menu. Insets define the minimum margin for these components
@@ -1146,13 +1171,14 @@
* @see #getContentInsetStart()
* @see #getContentInsetEnd()
* @see #getContentInsetRight()
+ * @attr ref android.R.styleable#Toolbar_contentInsetLeft
*/
public int getContentInsetLeft() {
return mContentInsets.getLeft();
}
/**
- * Get the right content inset for this toolbar.
+ * Gets the right content inset for this toolbar.
*
* <p>The content inset affects the valid area for Toolbar content other than
* the navigation button and menu. Insets define the minimum margin for these components
@@ -1165,11 +1191,160 @@
* @see #getContentInsetStart()
* @see #getContentInsetEnd()
* @see #getContentInsetLeft()
+ * @attr ref android.R.styleable#Toolbar_contentInsetRight
*/
public int getContentInsetRight() {
return mContentInsets.getRight();
}
+ /**
+ * Gets the start content inset to use when a navigation button is present.
+ *
+ * <p>Different content insets are often called for when additional buttons are present
+ * in the toolbar, as well as at different toolbar sizes. The larger value of
+ * {@link #getContentInsetStart()} and this value will be used during layout.</p>
+ *
+ * @return the start content inset used when a navigation icon has been set in pixels
+ *
+ * @see #setContentInsetStartWithNavigation(int)
+ * @attr ref android.R.styleable#Toolbar_contentInsetStartWithNavigation
+ */
+ public int getContentInsetStartWithNavigation() {
+ return mContentInsetStartWithNavigation != RtlSpacingHelper.UNDEFINED
+ ? mContentInsetStartWithNavigation
+ : getContentInsetStart();
+ }
+
+ /**
+ * Sets the start content inset to use when a navigation button is present.
+ *
+ * <p>Different content insets are often called for when additional buttons are present
+ * in the toolbar, as well as at different toolbar sizes. The larger value of
+ * {@link #getContentInsetStart()} and this value will be used during layout.</p>
+ *
+ * @param insetStartWithNavigation the inset to use when a navigation icon has been set
+ * in pixels
+ *
+ * @see #getContentInsetStartWithNavigation()
+ * @attr ref android.R.styleable#Toolbar_contentInsetStartWithNavigation
+ */
+ public void setContentInsetStartWithNavigation(int insetStartWithNavigation) {
+ if (insetStartWithNavigation < 0) {
+ insetStartWithNavigation = RtlSpacingHelper.UNDEFINED;
+ }
+ if (insetStartWithNavigation != mContentInsetStartWithNavigation) {
+ mContentInsetStartWithNavigation = insetStartWithNavigation;
+ if (getNavigationIcon() != null) {
+ requestLayout();
+ }
+ }
+ }
+
+ /**
+ * Gets the end content inset to use when action buttons are present.
+ *
+ * <p>Different content insets are often called for when additional buttons are present
+ * in the toolbar, as well as at different toolbar sizes. The larger value of
+ * {@link #getContentInsetEnd()} and this value will be used during layout.</p>
+ *
+ * @return the end content inset used when a menu has been set in pixels
+ *
+ * @see #setContentInsetEndWithActions(int)
+ * @attr ref android.R.styleable#Toolbar_contentInsetEndWithActions
+ */
+ public int getContentInsetEndWithActions() {
+ return mContentInsetEndWithActions != RtlSpacingHelper.UNDEFINED
+ ? mContentInsetEndWithActions
+ : getContentInsetEnd();
+ }
+
+ /**
+ * Sets the start content inset to use when action buttons are present.
+ *
+ * <p>Different content insets are often called for when additional buttons are present
+ * in the toolbar, as well as at different toolbar sizes. The larger value of
+ * {@link #getContentInsetEnd()} and this value will be used during layout.</p>
+ *
+ * @param insetEndWithActions the inset to use when a menu has been set in pixels
+ *
+ * @see #setContentInsetEndWithActions(int)
+ * @attr ref android.R.styleable#Toolbar_contentInsetEndWithActions
+ */
+ public void setContentInsetEndWithActions(int insetEndWithActions) {
+ if (insetEndWithActions < 0) {
+ insetEndWithActions = RtlSpacingHelper.UNDEFINED;
+ }
+ if (insetEndWithActions != mContentInsetEndWithActions) {
+ mContentInsetEndWithActions = insetEndWithActions;
+ if (getNavigationIcon() != null) {
+ requestLayout();
+ }
+ }
+ }
+
+ /**
+ * Gets the content inset that will be used on the starting side of the bar in the current
+ * toolbar configuration.
+ *
+ * @return the current content inset start in pixels
+ *
+ * @see #getContentInsetStartWithNavigation()
+ */
+ public int getCurrentContentInsetStart() {
+ return getNavigationIcon() != null
+ ? Math.max(getContentInsetStart(), Math.max(mContentInsetStartWithNavigation, 0))
+ : getContentInsetStart();
+ }
+
+ /**
+ * Gets the content inset that will be used on the ending side of the bar in the current
+ * toolbar configuration.
+ *
+ * @return the current content inset end in pixels
+ *
+ * @see #getContentInsetEndWithActions()
+ */
+ public int getCurrentContentInsetEnd() {
+ boolean hasActions = false;
+ if (mMenuView != null) {
+ final MenuBuilder mb = mMenuView.peekMenu();
+ hasActions = mb != null && mb.hasVisibleItems();
+ }
+ return hasActions
+ ? Math.max(getContentInsetEnd(), Math.max(mContentInsetEndWithActions, 0))
+ : getContentInsetEnd();
+ }
+
+ /**
+ * Gets the content inset that will be used on the left side of the bar in the current
+ * toolbar configuration.
+ *
+ * @return the current content inset left in pixels
+ *
+ * @see #getContentInsetStartWithNavigation()
+ * @see #getContentInsetEndWithActions()
+ */
+ public int getCurrentContentInsetLeft() {
+ return isLayoutRtl()
+ ? getCurrentContentInsetEnd()
+ : getCurrentContentInsetStart();
+ }
+
+ /**
+ * Gets the content inset that will be used on the right side of the bar in the current
+ * toolbar configuration.
+ *
+ * @return the current content inset right in pixels
+ *
+ * @see #getContentInsetStartWithNavigation()
+ * @see #getContentInsetEndWithActions()
+ */
+ public int getCurrentContentInsetRight() {
+ return isLayoutRtl()
+ ? getCurrentContentInsetStart()
+ : getCurrentContentInsetEnd();
+ }
+
private void ensureNavButtonView() {
if (mNavButtonView == null) {
mNavButtonView = new ImageButton(getContext(), null, 0, mNavButtonStyle);
@@ -1406,7 +1581,7 @@
childState = combineMeasuredStates(childState, mCollapseButtonView.getMeasuredState());
}
- final int contentInsetStart = getContentInsetStart();
+ final int contentInsetStart = getCurrentContentInsetStart();
width += Math.max(contentInsetStart, navWidth);
collapsingMargins[marginStartIndex] = Math.max(0, contentInsetStart - navWidth);
@@ -1420,7 +1595,7 @@
childState = combineMeasuredStates(childState, mMenuView.getMeasuredState());
}
- final int contentInsetEnd = getContentInsetEnd();
+ final int contentInsetEnd = getCurrentContentInsetEnd();
width += Math.max(contentInsetEnd, menuWidth);
collapsingMargins[marginEndIndex] = Math.max(0, contentInsetEnd - menuWidth);
@@ -1543,10 +1718,12 @@
}
}
- collapsingMargins[0] = Math.max(0, getContentInsetLeft() - left);
- collapsingMargins[1] = Math.max(0, getContentInsetRight() - (width - paddingRight - right));
- left = Math.max(left, getContentInsetLeft());
- right = Math.min(right, width - paddingRight - getContentInsetRight());
+ final int contentInsetLeft = getCurrentContentInsetLeft();
+ final int contentInsetRight = getCurrentContentInsetRight();
+ collapsingMargins[0] = Math.max(0, contentInsetLeft - left);
+ collapsingMargins[1] = Math.max(0, contentInsetRight - (width - paddingRight - right));
+ left = Math.max(left, contentInsetLeft);
+ right = Math.min(right, width - paddingRight - contentInsetRight);
if (shouldLayout(mExpandedActionView)) {
if (isRtl) {
diff --git a/core/java/com/android/internal/app/AlertController.java b/core/java/com/android/internal/app/AlertController.java
index 753c069..b7ac600 100644
--- a/core/java/com/android/internal/app/AlertController.java
+++ b/core/java/com/android/internal/app/AlertController.java
@@ -516,9 +516,15 @@
}
// Only show the divider if we have a title.
- final View divider;
+ View divider = null;
if (mMessage != null || mListView != null || hasCustomPanel) {
- divider = topPanel.findViewById(R.id.titleDivider);
+ if (!hasCustomPanel) {
+ divider = topPanel.findViewById(R.id.titleDividerNoCustom);
+ }
+ if (divider == null) {
+ divider = topPanel.findViewById(R.id.titleDivider);
+ }
+
} else {
divider = topPanel.findViewById(R.id.titleDividerTop);
}
@@ -526,6 +532,17 @@
if (divider != null) {
divider.setVisibility(View.VISIBLE);
}
+ } else {
+ if (contentPanel != null) {
+ final View spacer = contentPanel.findViewById(R.id.textSpacerNoTitle);
+ if (spacer != null) {
+ spacer.setVisibility(View.VISIBLE);
+ }
+ }
+ }
+
+ if (mListView instanceof RecycleListView) {
+ ((RecycleListView) mListView).setHasDecor(hasTopPanel, hasButtonPanel);
}
// Update scroll indicators as needed.
@@ -861,23 +878,34 @@
}
public static class RecycleListView extends ListView {
+ private final int mPaddingTopNoTitle;
+ private final int mPaddingBottomNoButtons;
+
boolean mRecycleOnMeasure = true;
public RecycleListView(Context context) {
- super(context);
+ this(context, null);
}
public RecycleListView(Context context, AttributeSet attrs) {
super(context, attrs);
+
+ final TypedArray ta = context.obtainStyledAttributes(
+ attrs, R.styleable.RecycleListView);
+ mPaddingBottomNoButtons = ta.getDimensionPixelOffset(
+ R.styleable.RecycleListView_paddingBottomNoButtons, -1);
+ mPaddingTopNoTitle = ta.getDimensionPixelOffset(
+ R.styleable.RecycleListView_paddingTopNoTitle, -1);
}
- public RecycleListView(Context context, AttributeSet attrs, int defStyleAttr) {
- super(context, attrs, defStyleAttr);
- }
-
- public RecycleListView(
- Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
- super(context, attrs, defStyleAttr, defStyleRes);
+ public void setHasDecor(boolean hasTitle, boolean hasButtons) {
+ if (!hasButtons || !hasTitle) {
+ final int paddingLeft = getPaddingLeft();
+ final int paddingTop = hasTitle ? getPaddingTop() : mPaddingTopNoTitle;
+ final int paddingRight = getPaddingRight();
+ final int paddingBottom = hasButtons ? getPaddingBottom() : mPaddingBottomNoButtons;
+ setPadding(paddingLeft, paddingTop, paddingRight, paddingBottom);
+ }
}
@Override
diff --git a/core/java/com/android/internal/app/LocaleHelper.java b/core/java/com/android/internal/app/LocaleHelper.java
index d8d6e56..a9d5113 100644
--- a/core/java/com/android/internal/app/LocaleHelper.java
+++ b/core/java/com/android/internal/app/LocaleHelper.java
@@ -181,6 +181,7 @@
public static final class LocaleInfoComparator implements Comparator<LocaleStore.LocaleInfo> {
private final Collator mCollator;
private final boolean mCountryMode;
+ private static final String PREFIX_ARABIC = "\u0627\u0644"; // ALEF-LAM, ال
/**
* Constructor.
@@ -192,6 +193,20 @@
mCountryMode = countryMode;
}
+ /*
+ * The Arabic collation should ignore Alef-Lam at the beginning (b/26277596)
+ *
+ * We look at the label's locale, not the current system locale.
+ * This is because the name of the Arabic language itself is in Arabic,
+ * and starts with Alef-Lam, no matter what the system locale is.
+ */
+ private String removePrefixForCompare(Locale locale, String str) {
+ if ("ar".equals(locale.getLanguage()) && str.startsWith(PREFIX_ARABIC)) {
+ return str.substring(PREFIX_ARABIC.length());
+ }
+ return str;
+ }
+
/**
* Compares its two arguments for order.
*
@@ -204,9 +219,11 @@
public int compare(LocaleStore.LocaleInfo lhs, LocaleStore.LocaleInfo rhs) {
// We don't care about the various suggestion types, just "suggested" (!= 0)
// and "all others" (== 0)
- if (mCountryMode || (lhs.isSuggested() == rhs.isSuggested())) {
+ if (lhs.isSuggested() == rhs.isSuggested()) {
// They are in the same "bucket" (suggested / others), so we compare the text
- return mCollator.compare(lhs.getLabel(mCountryMode), rhs.getLabel(mCountryMode));
+ return mCollator.compare(
+ removePrefixForCompare(lhs.getLocale(), lhs.getLabel(mCountryMode)),
+ removePrefixForCompare(rhs.getLocale(), rhs.getLabel(mCountryMode)));
} else {
// One locale is suggested and one is not, so we put them in different "buckets"
return lhs.isSuggested() ? -1 : 1;
diff --git a/core/java/com/android/internal/app/LocaleStore.java b/core/java/com/android/internal/app/LocaleStore.java
index c4e6675..7803e52 100644
--- a/core/java/com/android/internal/app/LocaleStore.java
+++ b/core/java/com/android/internal/app/LocaleStore.java
@@ -31,8 +31,9 @@
private static boolean sFullyInitialized = false;
public static class LocaleInfo {
- private static final int SUGGESTION_TYPE_NONE = 0x00;
- private static final int SUGGESTION_TYPE_SIM = 0x01;
+ private static final int SUGGESTION_TYPE_NONE = 0;
+ private static final int SUGGESTION_TYPE_SIM = 1 << 0;
+ private static final int SUGGESTION_TYPE_CFG = 1 << 1;
private final Locale mLocale;
private final Locale mParent;
@@ -273,6 +274,22 @@
final HashSet<String> localizedLocales = new HashSet<>();
for (String localeId : LocalePicker.getSystemAssetLocales()) {
LocaleInfo li = new LocaleInfo(localeId);
+ final String country = li.getLocale().getCountry();
+ // All this is to figure out if we should suggest a country
+ if (!country.isEmpty()) {
+ LocaleInfo cachedLocale = null;
+ if (sLocaleCache.containsKey(li.getId())) { // the simple case, e.g. fr-CH
+ cachedLocale = sLocaleCache.get(li.getId());
+ } else { // e.g. zh-TW localized, zh-Hant-TW in cache
+ final String langScriptCtry = li.getLangScriptKey() + "-" + country;
+ if (sLocaleCache.containsKey(langScriptCtry)) {
+ cachedLocale = sLocaleCache.get(langScriptCtry);
+ }
+ }
+ if (cachedLocale != null) {
+ cachedLocale.mSuggestionFlags |= LocaleInfo.SUGGESTION_TYPE_CFG;
+ }
+ }
localizedLocales.add(li.getLangScriptKey());
}
diff --git a/core/java/com/android/internal/app/ProcessMap.java b/core/java/com/android/internal/app/ProcessMap.java
index 23a8bd7..81036f7 100644
--- a/core/java/com/android/internal/app/ProcessMap.java
+++ b/core/java/com/android/internal/app/ProcessMap.java
@@ -54,4 +54,8 @@
public ArrayMap<String, SparseArray<E>> getMap() {
return mMap;
}
+
+ public int size() {
+ return mMap.size();
+ }
}
diff --git a/core/java/com/android/internal/app/ProcessStats.java b/core/java/com/android/internal/app/ProcessStats.java
deleted file mode 100644
index 17ca904d..0000000
--- a/core/java/com/android/internal/app/ProcessStats.java
+++ /dev/null
@@ -1,3794 +0,0 @@
-/*
- * Copyright (C) 2013 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.app;
-
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.os.SystemClock;
-import android.os.SystemProperties;
-import android.os.UserHandle;
-import android.text.format.DateFormat;
-import android.util.ArrayMap;
-import android.util.ArraySet;
-import android.util.DebugUtils;
-import android.util.Log;
-import android.util.Slog;
-import android.util.SparseArray;
-import android.util.TimeUtils;
-
-import com.android.internal.util.GrowingArrayUtils;
-
-import dalvik.system.VMRuntime;
-import libcore.util.EmptyArray;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.PrintWriter;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.Objects;
-
-public final class ProcessStats implements Parcelable {
- static final String TAG = "ProcessStats";
- static final boolean DEBUG = false;
- static final boolean DEBUG_PARCEL = false;
-
- public static final String SERVICE_NAME = "procstats";
-
- // How often the service commits its data, giving the minimum batching
- // that is done.
- public static long COMMIT_PERIOD = 3*60*60*1000; // Commit current stats every 3 hours
-
- // Minimum uptime period before committing. If the COMMIT_PERIOD has elapsed but
- // the total uptime has not exceeded this amount, then the commit will be held until
- // it is reached.
- public static long COMMIT_UPTIME_PERIOD = 60*60*1000; // Must have at least 1 hour elapsed
-
- public static final int STATE_NOTHING = -1;
- public static final int STATE_PERSISTENT = 0;
- public static final int STATE_TOP = 1;
- public static final int STATE_IMPORTANT_FOREGROUND = 2;
- public static final int STATE_IMPORTANT_BACKGROUND = 3;
- public static final int STATE_BACKUP = 4;
- public static final int STATE_HEAVY_WEIGHT = 5;
- public static final int STATE_SERVICE = 6;
- public static final int STATE_SERVICE_RESTARTING = 7;
- public static final int STATE_RECEIVER = 8;
- public static final int STATE_HOME = 9;
- public static final int STATE_LAST_ACTIVITY = 10;
- public static final int STATE_CACHED_ACTIVITY = 11;
- public static final int STATE_CACHED_ACTIVITY_CLIENT = 12;
- public static final int STATE_CACHED_EMPTY = 13;
- public static final int STATE_COUNT = STATE_CACHED_EMPTY+1;
-
- public static final int PSS_SAMPLE_COUNT = 0;
- public static final int PSS_MINIMUM = 1;
- public static final int PSS_AVERAGE = 2;
- public static final int PSS_MAXIMUM = 3;
- public static final int PSS_USS_MINIMUM = 4;
- public static final int PSS_USS_AVERAGE = 5;
- public static final int PSS_USS_MAXIMUM = 6;
- public static final int PSS_COUNT = PSS_USS_MAXIMUM+1;
-
- public static final int SYS_MEM_USAGE_SAMPLE_COUNT = 0;
- public static final int SYS_MEM_USAGE_CACHED_MINIMUM = 1;
- public static final int SYS_MEM_USAGE_CACHED_AVERAGE = 2;
- public static final int SYS_MEM_USAGE_CACHED_MAXIMUM = 3;
- public static final int SYS_MEM_USAGE_FREE_MINIMUM = 4;
- public static final int SYS_MEM_USAGE_FREE_AVERAGE = 5;
- public static final int SYS_MEM_USAGE_FREE_MAXIMUM = 6;
- public static final int SYS_MEM_USAGE_ZRAM_MINIMUM = 7;
- public static final int SYS_MEM_USAGE_ZRAM_AVERAGE = 8;
- public static final int SYS_MEM_USAGE_ZRAM_MAXIMUM = 9;
- public static final int SYS_MEM_USAGE_KERNEL_MINIMUM = 10;
- public static final int SYS_MEM_USAGE_KERNEL_AVERAGE = 11;
- public static final int SYS_MEM_USAGE_KERNEL_MAXIMUM = 12;
- public static final int SYS_MEM_USAGE_NATIVE_MINIMUM = 13;
- public static final int SYS_MEM_USAGE_NATIVE_AVERAGE = 14;
- public static final int SYS_MEM_USAGE_NATIVE_MAXIMUM = 15;
- public static final int SYS_MEM_USAGE_COUNT = SYS_MEM_USAGE_NATIVE_MAXIMUM+1;
-
- public static final int ADJ_NOTHING = -1;
- public static final int ADJ_MEM_FACTOR_NORMAL = 0;
- public static final int ADJ_MEM_FACTOR_MODERATE = 1;
- public static final int ADJ_MEM_FACTOR_LOW = 2;
- public static final int ADJ_MEM_FACTOR_CRITICAL = 3;
- public static final int ADJ_MEM_FACTOR_COUNT = ADJ_MEM_FACTOR_CRITICAL+1;
- public static final int ADJ_SCREEN_MOD = ADJ_MEM_FACTOR_COUNT;
- public static final int ADJ_SCREEN_OFF = 0;
- public static final int ADJ_SCREEN_ON = ADJ_SCREEN_MOD;
- public static final int ADJ_COUNT = ADJ_SCREEN_ON*2;
-
- public static final int FLAG_COMPLETE = 1<<0;
- public static final int FLAG_SHUTDOWN = 1<<1;
- public static final int FLAG_SYSPROPS = 1<<2;
-
- public static final int[] ALL_MEM_ADJ = new int[] { ADJ_MEM_FACTOR_NORMAL,
- ADJ_MEM_FACTOR_MODERATE, ADJ_MEM_FACTOR_LOW, ADJ_MEM_FACTOR_CRITICAL };
-
- public static final int[] ALL_SCREEN_ADJ = new int[] { ADJ_SCREEN_OFF, ADJ_SCREEN_ON };
-
- public static final int[] NON_CACHED_PROC_STATES = new int[] {
- STATE_PERSISTENT, STATE_TOP, STATE_IMPORTANT_FOREGROUND,
- STATE_IMPORTANT_BACKGROUND, STATE_BACKUP, STATE_HEAVY_WEIGHT,
- STATE_SERVICE, STATE_SERVICE_RESTARTING, STATE_RECEIVER
- };
-
- public static final int[] BACKGROUND_PROC_STATES = new int[] {
- STATE_IMPORTANT_FOREGROUND, STATE_IMPORTANT_BACKGROUND, STATE_BACKUP,
- STATE_HEAVY_WEIGHT, STATE_SERVICE, STATE_SERVICE_RESTARTING, STATE_RECEIVER
- };
-
- // Map from process states to the states we track.
- static final int[] PROCESS_STATE_TO_STATE = new int[] {
- STATE_PERSISTENT, // ActivityManager.PROCESS_STATE_PERSISTENT
- STATE_PERSISTENT, // ActivityManager.PROCESS_STATE_PERSISTENT_UI
- STATE_TOP, // ActivityManager.PROCESS_STATE_TOP
- STATE_IMPORTANT_FOREGROUND, // ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE
- STATE_IMPORTANT_FOREGROUND, // ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE
- STATE_TOP, // ActivityManager.PROCESS_STATE_TOP_SLEEPING
- STATE_IMPORTANT_FOREGROUND, // ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND
- STATE_IMPORTANT_BACKGROUND, // ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND
- STATE_BACKUP, // ActivityManager.PROCESS_STATE_BACKUP
- STATE_HEAVY_WEIGHT, // ActivityManager.PROCESS_STATE_HEAVY_WEIGHT
- STATE_SERVICE, // ActivityManager.PROCESS_STATE_SERVICE
- STATE_RECEIVER, // ActivityManager.PROCESS_STATE_RECEIVER
- STATE_HOME, // ActivityManager.PROCESS_STATE_HOME
- STATE_LAST_ACTIVITY, // ActivityManager.PROCESS_STATE_LAST_ACTIVITY
- STATE_CACHED_ACTIVITY, // ActivityManager.PROCESS_STATE_CACHED_ACTIVITY
- STATE_CACHED_ACTIVITY_CLIENT, // ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT
- STATE_CACHED_EMPTY, // ActivityManager.PROCESS_STATE_CACHED_EMPTY
- };
-
- public static final int[] ALL_PROC_STATES = new int[] { STATE_PERSISTENT,
- STATE_TOP, STATE_IMPORTANT_FOREGROUND, STATE_IMPORTANT_BACKGROUND, STATE_BACKUP,
- STATE_HEAVY_WEIGHT, STATE_SERVICE, STATE_SERVICE_RESTARTING, STATE_RECEIVER,
- STATE_HOME, STATE_LAST_ACTIVITY, STATE_CACHED_ACTIVITY,
- STATE_CACHED_ACTIVITY_CLIENT, STATE_CACHED_EMPTY
- };
-
- static final String[] STATE_NAMES = new String[] {
- "Persist", "Top ", "ImpFg ", "ImpBg ",
- "Backup ", "HeavyWt", "Service", "ServRst",
- "Receivr", "Home ",
- "LastAct", "CchAct ", "CchCAct", "CchEmty"
- };
-
- public static final String[] ADJ_SCREEN_NAMES_CSV = new String[] {
- "off", "on"
- };
-
- public static final String[] ADJ_MEM_NAMES_CSV = new String[] {
- "norm", "mod", "low", "crit"
- };
-
- public static final String[] STATE_NAMES_CSV = new String[] {
- "pers", "top", "impfg", "impbg", "backup", "heavy",
- "service", "service-rs", "receiver", "home", "lastact",
- "cch-activity", "cch-aclient", "cch-empty"
- };
-
- static final String[] ADJ_SCREEN_TAGS = new String[] {
- "0", "1"
- };
-
- static final String[] ADJ_MEM_TAGS = new String[] {
- "n", "m", "l", "c"
- };
-
- static final String[] STATE_TAGS = new String[] {
- "p", "t", "f", "b", "u", "w",
- "s", "x", "r", "h", "l", "a", "c", "e"
- };
-
- static final String CSV_SEP = "\t";
-
- // Current version of the parcel format.
- private static final int PARCEL_VERSION = 18;
- // In-memory Parcel magic number, used to detect attempts to unmarshall bad data
- private static final int MAGIC = 0x50535453;
-
- // Where the "type"/"state" part of the data appears in an offset integer.
- static int OFFSET_TYPE_SHIFT = 0;
- static int OFFSET_TYPE_MASK = 0xff;
- // Where the "which array" part of the data appears in an offset integer.
- static int OFFSET_ARRAY_SHIFT = 8;
- static int OFFSET_ARRAY_MASK = 0xff;
- // Where the "index into array" part of the data appears in an offset integer.
- static int OFFSET_INDEX_SHIFT = 16;
- static int OFFSET_INDEX_MASK = 0xffff;
-
- public String mReadError;
- public String mTimePeriodStartClockStr;
- public int mFlags;
-
- public final ProcessMap<SparseArray<PackageState>> mPackages
- = new ProcessMap<SparseArray<PackageState>>();
- public final ProcessMap<ProcessState> mProcesses = new ProcessMap<ProcessState>();
-
- public final long[] mMemFactorDurations = new long[ADJ_COUNT];
- public int mMemFactor = STATE_NOTHING;
- public long mStartTime;
-
- public int[] mSysMemUsageTable = null;
- public int mSysMemUsageTableSize = 0;
- public final long[] mSysMemUsageArgs = new long[SYS_MEM_USAGE_COUNT];
-
- public long mTimePeriodStartClock;
- public long mTimePeriodStartRealtime;
- public long mTimePeriodEndRealtime;
- public long mTimePeriodStartUptime;
- public long mTimePeriodEndUptime;
- String mRuntime;
- boolean mRunning;
-
- static final int LONGS_SIZE = 4096;
- final ArrayList<long[]> mLongs = new ArrayList<long[]>();
- int mNextLong;
-
- int[] mAddLongTable;
- int mAddLongTableSize;
-
- // For writing parcels.
- ArrayMap<String, Integer> mCommonStringToIndex;
-
- // For reading parcels.
- ArrayList<String> mIndexToCommonString;
-
- public ProcessStats(boolean running) {
- mRunning = running;
- reset();
- }
-
- public ProcessStats(Parcel in) {
- reset();
- readFromParcel(in);
- }
-
- public void add(ProcessStats other) {
- ArrayMap<String, SparseArray<SparseArray<PackageState>>> pkgMap = other.mPackages.getMap();
- for (int ip=0; ip<pkgMap.size(); ip++) {
- final String pkgName = pkgMap.keyAt(ip);
- final SparseArray<SparseArray<PackageState>> uids = pkgMap.valueAt(ip);
- for (int iu=0; iu<uids.size(); iu++) {
- final int uid = uids.keyAt(iu);
- final SparseArray<PackageState> versions = uids.valueAt(iu);
- for (int iv=0; iv<versions.size(); iv++) {
- final int vers = versions.keyAt(iv);
- final PackageState otherState = versions.valueAt(iv);
- final int NPROCS = otherState.mProcesses.size();
- final int NSRVS = otherState.mServices.size();
- for (int iproc=0; iproc<NPROCS; iproc++) {
- ProcessState otherProc = otherState.mProcesses.valueAt(iproc);
- if (otherProc.mCommonProcess != otherProc) {
- if (DEBUG) Slog.d(TAG, "Adding pkg " + pkgName + " uid " + uid
- + " vers " + vers + " proc " + otherProc.mName);
- ProcessState thisProc = getProcessStateLocked(pkgName, uid, vers,
- otherProc.mName);
- if (thisProc.mCommonProcess == thisProc) {
- if (DEBUG) Slog.d(TAG, "Existing process is single-package, splitting");
- thisProc.mMultiPackage = true;
- long now = SystemClock.uptimeMillis();
- final PackageState pkgState = getPackageStateLocked(pkgName, uid,
- vers);
- thisProc = thisProc.clone(thisProc.mPackage, now);
- pkgState.mProcesses.put(thisProc.mName, thisProc);
- }
- thisProc.add(otherProc);
- }
- }
- for (int isvc=0; isvc<NSRVS; isvc++) {
- ServiceState otherSvc = otherState.mServices.valueAt(isvc);
- if (DEBUG) Slog.d(TAG, "Adding pkg " + pkgName + " uid " + uid
- + " service " + otherSvc.mName);
- ServiceState thisSvc = getServiceStateLocked(pkgName, uid, vers,
- otherSvc.mProcessName, otherSvc.mName);
- thisSvc.add(otherSvc);
- }
- }
- }
- }
-
- ArrayMap<String, SparseArray<ProcessState>> procMap = other.mProcesses.getMap();
- for (int ip=0; ip<procMap.size(); ip++) {
- SparseArray<ProcessState> uids = procMap.valueAt(ip);
- for (int iu=0; iu<uids.size(); iu++) {
- int uid = uids.keyAt(iu);
- ProcessState otherProc = uids.valueAt(iu);
- ProcessState thisProc = mProcesses.get(otherProc.mName, uid);
- if (DEBUG) Slog.d(TAG, "Adding uid " + uid + " proc " + otherProc.mName);
- if (thisProc == null) {
- if (DEBUG) Slog.d(TAG, "Creating new process!");
- thisProc = new ProcessState(this, otherProc.mPackage, uid, otherProc.mVersion,
- otherProc.mName);
- mProcesses.put(otherProc.mName, uid, thisProc);
- PackageState thisState = getPackageStateLocked(otherProc.mPackage, uid,
- otherProc.mVersion);
- if (!thisState.mProcesses.containsKey(otherProc.mName)) {
- thisState.mProcesses.put(otherProc.mName, thisProc);
- }
- }
- thisProc.add(otherProc);
- }
- }
-
- for (int i=0; i<ADJ_COUNT; i++) {
- if (DEBUG) Slog.d(TAG, "Total duration #" + i + " inc by "
- + other.mMemFactorDurations[i] + " from "
- + mMemFactorDurations[i]);
- mMemFactorDurations[i] += other.mMemFactorDurations[i];
- }
-
- for (int i=0; i<other.mSysMemUsageTableSize; i++) {
- int ent = other.mSysMemUsageTable[i];
- int state = (ent>>OFFSET_TYPE_SHIFT)&OFFSET_TYPE_MASK;
- long[] longs = other.mLongs.get((ent>>OFFSET_ARRAY_SHIFT)&OFFSET_ARRAY_MASK);
- addSysMemUsage(state, longs, ((ent >> OFFSET_INDEX_SHIFT) & OFFSET_INDEX_MASK));
- }
-
- if (other.mTimePeriodStartClock < mTimePeriodStartClock) {
- mTimePeriodStartClock = other.mTimePeriodStartClock;
- mTimePeriodStartClockStr = other.mTimePeriodStartClockStr;
- }
- mTimePeriodEndRealtime += other.mTimePeriodEndRealtime - other.mTimePeriodStartRealtime;
- mTimePeriodEndUptime += other.mTimePeriodEndUptime - other.mTimePeriodStartUptime;
- }
-
- public void addSysMemUsage(long cachedMem, long freeMem, long zramMem, long kernelMem,
- long nativeMem) {
- if (mMemFactor != STATE_NOTHING) {
- int state = mMemFactor * STATE_COUNT;
- mSysMemUsageArgs[SYS_MEM_USAGE_SAMPLE_COUNT] = 1;
- for (int i=0; i<3; i++) {
- mSysMemUsageArgs[SYS_MEM_USAGE_CACHED_MINIMUM + i] = cachedMem;
- mSysMemUsageArgs[SYS_MEM_USAGE_FREE_MINIMUM + i] = freeMem;
- mSysMemUsageArgs[SYS_MEM_USAGE_ZRAM_MINIMUM + i] = zramMem;
- mSysMemUsageArgs[SYS_MEM_USAGE_KERNEL_MINIMUM + i] = kernelMem;
- mSysMemUsageArgs[SYS_MEM_USAGE_NATIVE_MINIMUM + i] = nativeMem;
- }
- addSysMemUsage(state, mSysMemUsageArgs, 0);
- }
- }
-
- void addSysMemUsage(int state, long[] data, int dataOff) {
- int idx = binarySearch(mSysMemUsageTable, mSysMemUsageTableSize, state);
- int off;
- if (idx >= 0) {
- off = mSysMemUsageTable[idx];
- } else {
- mAddLongTable = mSysMemUsageTable;
- mAddLongTableSize = mSysMemUsageTableSize;
- off = addLongData(~idx, state, SYS_MEM_USAGE_COUNT);
- mSysMemUsageTable = mAddLongTable;
- mSysMemUsageTableSize = mAddLongTableSize;
- }
- long[] longs = mLongs.get((off>>OFFSET_ARRAY_SHIFT)&OFFSET_ARRAY_MASK);
- idx = (off>>OFFSET_INDEX_SHIFT)&OFFSET_INDEX_MASK;
- addSysMemUsage(longs, idx, data, dataOff);
- }
-
- static void addSysMemUsage(long[] dstData, int dstOff, long[] addData, int addOff) {
- final long dstCount = dstData[dstOff+SYS_MEM_USAGE_SAMPLE_COUNT];
- final long addCount = addData[addOff+SYS_MEM_USAGE_SAMPLE_COUNT];
- if (dstCount == 0) {
- dstData[dstOff+SYS_MEM_USAGE_SAMPLE_COUNT] = addCount;
- for (int i=SYS_MEM_USAGE_CACHED_MINIMUM; i<SYS_MEM_USAGE_COUNT; i++) {
- dstData[dstOff+i] = addData[addOff+i];
- }
- } else if (addCount > 0) {
- dstData[dstOff+SYS_MEM_USAGE_SAMPLE_COUNT] = dstCount + addCount;
- for (int i=SYS_MEM_USAGE_CACHED_MINIMUM; i<SYS_MEM_USAGE_COUNT; i+=3) {
- if (dstData[dstOff+i] > addData[addOff+i]) {
- dstData[dstOff+i] = addData[addOff+i];
- }
- dstData[dstOff+i+1] = (long)(
- ((dstData[dstOff+i+1]*(double)dstCount)
- + (addData[addOff+i+1]*(double)addCount))
- / (dstCount+addCount) );
- if (dstData[dstOff+i+2] < addData[addOff+i+2]) {
- dstData[dstOff+i+2] = addData[addOff+i+2];
- }
- }
- }
- }
-
- public static final Parcelable.Creator<ProcessStats> CREATOR
- = new Parcelable.Creator<ProcessStats>() {
- public ProcessStats createFromParcel(Parcel in) {
- return new ProcessStats(in);
- }
-
- public ProcessStats[] newArray(int size) {
- return new ProcessStats[size];
- }
- };
-
- private static void printScreenLabel(PrintWriter pw, int offset) {
- switch (offset) {
- case ADJ_NOTHING:
- pw.print(" ");
- break;
- case ADJ_SCREEN_OFF:
- pw.print("SOff/");
- break;
- case ADJ_SCREEN_ON:
- pw.print("SOn /");
- break;
- default:
- pw.print("????/");
- break;
- }
- }
-
- public static void printScreenLabelCsv(PrintWriter pw, int offset) {
- switch (offset) {
- case ADJ_NOTHING:
- break;
- case ADJ_SCREEN_OFF:
- pw.print(ADJ_SCREEN_NAMES_CSV[0]);
- break;
- case ADJ_SCREEN_ON:
- pw.print(ADJ_SCREEN_NAMES_CSV[1]);
- break;
- default:
- pw.print("???");
- break;
- }
- }
-
- private static void printMemLabel(PrintWriter pw, int offset, char sep) {
- switch (offset) {
- case ADJ_NOTHING:
- pw.print(" ");
- if (sep != 0) pw.print(' ');
- break;
- case ADJ_MEM_FACTOR_NORMAL:
- pw.print("Norm");
- if (sep != 0) pw.print(sep);
- break;
- case ADJ_MEM_FACTOR_MODERATE:
- pw.print("Mod ");
- if (sep != 0) pw.print(sep);
- break;
- case ADJ_MEM_FACTOR_LOW:
- pw.print("Low ");
- if (sep != 0) pw.print(sep);
- break;
- case ADJ_MEM_FACTOR_CRITICAL:
- pw.print("Crit");
- if (sep != 0) pw.print(sep);
- break;
- default:
- pw.print("????");
- if (sep != 0) pw.print(sep);
- break;
- }
- }
-
- public static void printMemLabelCsv(PrintWriter pw, int offset) {
- if (offset >= ADJ_MEM_FACTOR_NORMAL) {
- if (offset <= ADJ_MEM_FACTOR_CRITICAL) {
- pw.print(ADJ_MEM_NAMES_CSV[offset]);
- } else {
- pw.print("???");
- }
- }
- }
-
- public static long dumpSingleTime(PrintWriter pw, String prefix, long[] durations,
- int curState, long curStartTime, long now) {
- long totalTime = 0;
- int printedScreen = -1;
- for (int iscreen=0; iscreen<ADJ_COUNT; iscreen+=ADJ_SCREEN_MOD) {
- int printedMem = -1;
- for (int imem=0; imem<ADJ_MEM_FACTOR_COUNT; imem++) {
- int state = imem+iscreen;
- long time = durations[state];
- String running = "";
- if (curState == state) {
- time += now - curStartTime;
- if (pw != null) {
- running = " (running)";
- }
- }
- if (time != 0) {
- if (pw != null) {
- pw.print(prefix);
- printScreenLabel(pw, printedScreen != iscreen
- ? iscreen : STATE_NOTHING);
- printedScreen = iscreen;
- printMemLabel(pw, printedMem != imem ? imem : STATE_NOTHING, (char)0);
- printedMem = imem;
- pw.print(": ");
- TimeUtils.formatDuration(time, pw); pw.println(running);
- }
- totalTime += time;
- }
- }
- }
- if (totalTime != 0 && pw != null) {
- pw.print(prefix);
- pw.print(" TOTAL: ");
- TimeUtils.formatDuration(totalTime, pw);
- pw.println();
- }
- return totalTime;
- }
-
- static void dumpAdjTimesCheckin(PrintWriter pw, String sep, long[] durations,
- int curState, long curStartTime, long now) {
- for (int iscreen=0; iscreen<ADJ_COUNT; iscreen+=ADJ_SCREEN_MOD) {
- for (int imem=0; imem<ADJ_MEM_FACTOR_COUNT; imem++) {
- int state = imem+iscreen;
- long time = durations[state];
- if (curState == state) {
- time += now - curStartTime;
- }
- if (time != 0) {
- printAdjTagAndValue(pw, state, time);
- }
- }
- }
- }
-
- static void dumpServiceTimeCheckin(PrintWriter pw, String label, String packageName,
- int uid, int vers, String serviceName, ServiceState svc, int serviceType, int opCount,
- int curState, long curStartTime, long now) {
- if (opCount <= 0) {
- return;
- }
- pw.print(label);
- pw.print(",");
- pw.print(packageName);
- pw.print(",");
- pw.print(uid);
- pw.print(",");
- pw.print(vers);
- pw.print(",");
- pw.print(serviceName);
- pw.print(",");
- pw.print(opCount);
- boolean didCurState = false;
- for (int i=0; i<svc.mDurationsTableSize; i++) {
- int off = svc.mDurationsTable[i];
- int type = (off>>OFFSET_TYPE_SHIFT)&OFFSET_TYPE_MASK;
- int memFactor = type / ServiceState.SERVICE_COUNT;
- type %= ServiceState.SERVICE_COUNT;
- if (type != serviceType) {
- continue;
- }
- long time = svc.mStats.getLong(off, 0);
- if (curState == memFactor) {
- didCurState = true;
- time += now - curStartTime;
- }
- printAdjTagAndValue(pw, memFactor, time);
- }
- if (!didCurState && curState != STATE_NOTHING) {
- printAdjTagAndValue(pw, curState, now - curStartTime);
- }
- pw.println();
- }
-
- public static void computeProcessData(ProcessState proc, ProcessDataCollection data, long now) {
- data.totalTime = 0;
- data.numPss = data.minPss = data.avgPss = data.maxPss =
- data.minUss = data.avgUss = data.maxUss = 0;
- for (int is=0; is<data.screenStates.length; is++) {
- for (int im=0; im<data.memStates.length; im++) {
- for (int ip=0; ip<data.procStates.length; ip++) {
- int bucket = ((data.screenStates[is] + data.memStates[im]) * STATE_COUNT)
- + data.procStates[ip];
- data.totalTime += proc.getDuration(bucket, now);
- long samples = proc.getPssSampleCount(bucket);
- if (samples > 0) {
- long minPss = proc.getPssMinimum(bucket);
- long avgPss = proc.getPssAverage(bucket);
- long maxPss = proc.getPssMaximum(bucket);
- long minUss = proc.getPssUssMinimum(bucket);
- long avgUss = proc.getPssUssAverage(bucket);
- long maxUss = proc.getPssUssMaximum(bucket);
- if (data.numPss == 0) {
- data.minPss = minPss;
- data.avgPss = avgPss;
- data.maxPss = maxPss;
- data.minUss = minUss;
- data.avgUss = avgUss;
- data.maxUss = maxUss;
- } else {
- if (minPss < data.minPss) {
- data.minPss = minPss;
- }
- data.avgPss = (long)( ((data.avgPss*(double)data.numPss)
- + (avgPss*(double)samples)) / (data.numPss+samples) );
- if (maxPss > data.maxPss) {
- data.maxPss = maxPss;
- }
- if (minUss < data.minUss) {
- data.minUss = minUss;
- }
- data.avgUss = (long)( ((data.avgUss*(double)data.numPss)
- + (avgUss*(double)samples)) / (data.numPss+samples) );
- if (maxUss > data.maxUss) {
- data.maxUss = maxUss;
- }
- }
- data.numPss += samples;
- }
- }
- }
- }
- }
-
- static long computeProcessTimeLocked(ProcessState proc, int[] screenStates, int[] memStates,
- int[] procStates, long now) {
- long totalTime = 0;
- /*
- for (int i=0; i<proc.mDurationsTableSize; i++) {
- int val = proc.mDurationsTable[i];
- totalTime += proc.mState.getLong(val, 0);
- if ((val&0xff) == proc.mCurState) {
- totalTime += now - proc.mStartTime;
- }
- }
- */
- for (int is=0; is<screenStates.length; is++) {
- for (int im=0; im<memStates.length; im++) {
- for (int ip=0; ip<procStates.length; ip++) {
- int bucket = ((screenStates[is] + memStates[im]) * STATE_COUNT)
- + procStates[ip];
- totalTime += proc.getDuration(bucket, now);
- }
- }
- }
- proc.mTmpTotalTime = totalTime;
- return totalTime;
- }
-
- static class PssAggr {
- long pss = 0;
- long samples = 0;
-
- void add(long newPss, long newSamples) {
- pss = (long)( (pss*(double)samples) + (newPss*(double)newSamples) )
- / (samples+newSamples);
- samples += newSamples;
- }
- }
-
- public void computeTotalMemoryUse(TotalMemoryUseCollection data, long now) {
- data.totalTime = 0;
- for (int i=0; i<STATE_COUNT; i++) {
- data.processStateWeight[i] = 0;
- data.processStatePss[i] = 0;
- data.processStateTime[i] = 0;
- data.processStateSamples[i] = 0;
- }
- for (int i=0; i<SYS_MEM_USAGE_COUNT; i++) {
- data.sysMemUsage[i] = 0;
- }
- data.sysMemCachedWeight = 0;
- data.sysMemFreeWeight = 0;
- data.sysMemZRamWeight = 0;
- data.sysMemKernelWeight = 0;
- data.sysMemNativeWeight = 0;
- data.sysMemSamples = 0;
- long[] totalMemUsage = new long[SYS_MEM_USAGE_COUNT];
- for (int i=0; i<mSysMemUsageTableSize; i++) {
- int ent = mSysMemUsageTable[i];
- long[] longs = mLongs.get((ent>>OFFSET_ARRAY_SHIFT)&OFFSET_ARRAY_MASK);
- int idx = (ent >> OFFSET_INDEX_SHIFT) & OFFSET_INDEX_MASK;
- addSysMemUsage(totalMemUsage, 0, longs, idx);
- }
- for (int is=0; is<data.screenStates.length; is++) {
- for (int im=0; im<data.memStates.length; im++) {
- int memBucket = data.screenStates[is] + data.memStates[im];
- int stateBucket = memBucket * STATE_COUNT;
- long memTime = mMemFactorDurations[memBucket];
- if (mMemFactor == memBucket) {
- memTime += now - mStartTime;
- }
- data.totalTime += memTime;
- int sysIdx = binarySearch(mSysMemUsageTable, mSysMemUsageTableSize, stateBucket);
- long[] longs = totalMemUsage;
- int idx = 0;
- if (sysIdx >= 0) {
- int ent = mSysMemUsageTable[sysIdx];
- long[] tmpLongs = mLongs.get((ent>>OFFSET_ARRAY_SHIFT)&OFFSET_ARRAY_MASK);
- int tmpIdx = (ent >> OFFSET_INDEX_SHIFT) & OFFSET_INDEX_MASK;
- if (tmpLongs[tmpIdx+SYS_MEM_USAGE_SAMPLE_COUNT] >= 3) {
- addSysMemUsage(data.sysMemUsage, 0, longs, idx);
- longs = tmpLongs;
- idx = tmpIdx;
- }
- }
- data.sysMemCachedWeight += longs[idx+SYS_MEM_USAGE_CACHED_AVERAGE]
- * (double)memTime;
- data.sysMemFreeWeight += longs[idx+SYS_MEM_USAGE_FREE_AVERAGE]
- * (double)memTime;
- data.sysMemZRamWeight += longs[idx+SYS_MEM_USAGE_ZRAM_AVERAGE]
- * (double)memTime;
- data.sysMemKernelWeight += longs[idx+SYS_MEM_USAGE_KERNEL_AVERAGE]
- * (double)memTime;
- data.sysMemNativeWeight += longs[idx+SYS_MEM_USAGE_NATIVE_AVERAGE]
- * (double)memTime;
- data.sysMemSamples += longs[idx+SYS_MEM_USAGE_SAMPLE_COUNT];
- }
- }
- ArrayMap<String, SparseArray<ProcessState>> procMap = mProcesses.getMap();
- for (int iproc=0; iproc<procMap.size(); iproc++) {
- SparseArray<ProcessState> uids = procMap.valueAt(iproc);
- for (int iu=0; iu<uids.size(); iu++) {
- final ProcessState proc = uids.valueAt(iu);
- final PssAggr fgPss = new PssAggr();
- final PssAggr bgPss = new PssAggr();
- final PssAggr cachedPss = new PssAggr();
- boolean havePss = false;
- for (int i=0; i<proc.mDurationsTableSize; i++) {
- int off = proc.mDurationsTable[i];
- int type = (off>>OFFSET_TYPE_SHIFT)&OFFSET_TYPE_MASK;
- int procState = type % STATE_COUNT;
- long samples = proc.getPssSampleCount(type);
- if (samples > 0) {
- long avg = proc.getPssAverage(type);
- havePss = true;
- if (procState <= STATE_IMPORTANT_FOREGROUND) {
- fgPss.add(avg, samples);
- } else if (procState <= STATE_RECEIVER) {
- bgPss.add(avg, samples);
- } else {
- cachedPss.add(avg, samples);
- }
- }
- }
- if (!havePss) {
- continue;
- }
- boolean fgHasBg = false;
- boolean fgHasCached = false;
- boolean bgHasCached = false;
- if (fgPss.samples < 3 && bgPss.samples > 0) {
- fgHasBg = true;
- fgPss.add(bgPss.pss, bgPss.samples);
- }
- if (fgPss.samples < 3 && cachedPss.samples > 0) {
- fgHasCached = true;
- fgPss.add(cachedPss.pss, cachedPss.samples);
- }
- if (bgPss.samples < 3 && cachedPss.samples > 0) {
- bgHasCached = true;
- bgPss.add(cachedPss.pss, cachedPss.samples);
- }
- if (bgPss.samples < 3 && !fgHasBg && fgPss.samples > 0) {
- bgPss.add(fgPss.pss, fgPss.samples);
- }
- if (cachedPss.samples < 3 && !bgHasCached && bgPss.samples > 0) {
- cachedPss.add(bgPss.pss, bgPss.samples);
- }
- if (cachedPss.samples < 3 && !fgHasCached && fgPss.samples > 0) {
- cachedPss.add(fgPss.pss, fgPss.samples);
- }
- for (int i=0; i<proc.mDurationsTableSize; i++) {
- final int off = proc.mDurationsTable[i];
- final int type = (off>>OFFSET_TYPE_SHIFT)&OFFSET_TYPE_MASK;
- long time = getLong(off, 0);
- if (proc.mCurState == type) {
- time += now - proc.mStartTime;
- }
- final int procState = type % STATE_COUNT;
- data.processStateTime[procState] += time;
- long samples = proc.getPssSampleCount(type);
- long avg;
- if (samples > 0) {
- avg = proc.getPssAverage(type);
- } else if (procState <= STATE_IMPORTANT_FOREGROUND) {
- samples = fgPss.samples;
- avg = fgPss.pss;
- } else if (procState <= STATE_RECEIVER) {
- samples = bgPss.samples;
- avg = bgPss.pss;
- } else {
- samples = cachedPss.samples;
- avg = cachedPss.pss;
- }
- double newAvg = ( (data.processStatePss[procState]
- * (double)data.processStateSamples[procState])
- + (avg*(double)samples)
- ) / (data.processStateSamples[procState]+samples);
- data.processStatePss[procState] = (long)newAvg;
- data.processStateSamples[procState] += samples;
- data.processStateWeight[procState] += avg * (double)time;
- }
- }
- }
- }
-
- static void dumpProcessState(PrintWriter pw, String prefix, ProcessState proc,
- int[] screenStates, int[] memStates, int[] procStates, long now) {
- long totalTime = 0;
- int printedScreen = -1;
- for (int is=0; is<screenStates.length; is++) {
- int printedMem = -1;
- for (int im=0; im<memStates.length; im++) {
- for (int ip=0; ip<procStates.length; ip++) {
- final int iscreen = screenStates[is];
- final int imem = memStates[im];
- final int bucket = ((iscreen + imem) * STATE_COUNT) + procStates[ip];
- long time = proc.getDuration(bucket, now);
- String running = "";
- if (proc.mCurState == bucket) {
- running = " (running)";
- }
- if (time != 0) {
- pw.print(prefix);
- if (screenStates.length > 1) {
- printScreenLabel(pw, printedScreen != iscreen
- ? iscreen : STATE_NOTHING);
- printedScreen = iscreen;
- }
- if (memStates.length > 1) {
- printMemLabel(pw, printedMem != imem ? imem : STATE_NOTHING, '/');
- printedMem = imem;
- }
- pw.print(STATE_NAMES[procStates[ip]]); pw.print(": ");
- TimeUtils.formatDuration(time, pw); pw.println(running);
- totalTime += time;
- }
- }
- }
- }
- if (totalTime != 0) {
- pw.print(prefix);
- if (screenStates.length > 1) {
- printScreenLabel(pw, STATE_NOTHING);
- }
- if (memStates.length > 1) {
- printMemLabel(pw, STATE_NOTHING, '/');
- }
- pw.print("TOTAL : ");
- TimeUtils.formatDuration(totalTime, pw);
- pw.println();
- }
- }
-
- static void dumpProcessPss(PrintWriter pw, String prefix, ProcessState proc, int[] screenStates,
- int[] memStates, int[] procStates) {
- boolean printedHeader = false;
- int printedScreen = -1;
- for (int is=0; is<screenStates.length; is++) {
- int printedMem = -1;
- for (int im=0; im<memStates.length; im++) {
- for (int ip=0; ip<procStates.length; ip++) {
- final int iscreen = screenStates[is];
- final int imem = memStates[im];
- final int bucket = ((iscreen + imem) * STATE_COUNT) + procStates[ip];
- long count = proc.getPssSampleCount(bucket);
- if (count > 0) {
- if (!printedHeader) {
- pw.print(prefix);
- pw.print("PSS/USS (");
- pw.print(proc.mPssTableSize);
- pw.println(" entries):");
- printedHeader = true;
- }
- pw.print(prefix);
- pw.print(" ");
- if (screenStates.length > 1) {
- printScreenLabel(pw, printedScreen != iscreen
- ? iscreen : STATE_NOTHING);
- printedScreen = iscreen;
- }
- if (memStates.length > 1) {
- printMemLabel(pw, printedMem != imem ? imem : STATE_NOTHING, '/');
- printedMem = imem;
- }
- pw.print(STATE_NAMES[procStates[ip]]); pw.print(": ");
- pw.print(count);
- pw.print(" samples ");
- DebugUtils.printSizeValue(pw, proc.getPssMinimum(bucket) * 1024);
- pw.print(" ");
- DebugUtils.printSizeValue(pw, proc.getPssAverage(bucket) * 1024);
- pw.print(" ");
- DebugUtils.printSizeValue(pw, proc.getPssMaximum(bucket) * 1024);
- pw.print(" / ");
- DebugUtils.printSizeValue(pw, proc.getPssUssMinimum(bucket) * 1024);
- pw.print(" ");
- DebugUtils.printSizeValue(pw, proc.getPssUssAverage(bucket) * 1024);
- pw.print(" ");
- DebugUtils.printSizeValue(pw, proc.getPssUssMaximum(bucket) * 1024);
- pw.println();
- }
- }
- }
- }
- if (proc.mNumExcessiveWake != 0) {
- pw.print(prefix); pw.print("Killed for excessive wake locks: ");
- pw.print(proc.mNumExcessiveWake); pw.println(" times");
- }
- if (proc.mNumExcessiveCpu != 0) {
- pw.print(prefix); pw.print("Killed for excessive CPU use: ");
- pw.print(proc.mNumExcessiveCpu); pw.println(" times");
- }
- if (proc.mNumCachedKill != 0) {
- pw.print(prefix); pw.print("Killed from cached state: ");
- pw.print(proc.mNumCachedKill); pw.print(" times from pss ");
- DebugUtils.printSizeValue(pw, proc.mMinCachedKillPss * 1024); pw.print("-");
- DebugUtils.printSizeValue(pw, proc.mAvgCachedKillPss * 1024); pw.print("-");
- DebugUtils.printSizeValue(pw, proc.mMaxCachedKillPss * 1024); pw.println();
- }
- }
-
- long getSysMemUsageValue(int state, int index) {
- int idx = binarySearch(mSysMemUsageTable, mSysMemUsageTableSize, state);
- return idx >= 0 ? getLong(mSysMemUsageTable[idx], index) : 0;
- }
-
- void dumpSysMemUsageCategory(PrintWriter pw, String prefix, String label,
- int bucket, int index) {
- pw.print(prefix); pw.print(label);
- pw.print(": ");
- DebugUtils.printSizeValue(pw, getSysMemUsageValue(bucket, index) * 1024);
- pw.print(" min, ");
- DebugUtils.printSizeValue(pw, getSysMemUsageValue(bucket, index + 1) * 1024);
- pw.print(" avg, ");
- DebugUtils.printSizeValue(pw, getSysMemUsageValue(bucket, index+2) * 1024);
- pw.println(" max");
- }
-
- void dumpSysMemUsage(PrintWriter pw, String prefix, int[] screenStates,
- int[] memStates) {
- int printedScreen = -1;
- for (int is=0; is<screenStates.length; is++) {
- int printedMem = -1;
- for (int im=0; im<memStates.length; im++) {
- final int iscreen = screenStates[is];
- final int imem = memStates[im];
- final int bucket = ((iscreen + imem) * STATE_COUNT);
- long count = getSysMemUsageValue(bucket, SYS_MEM_USAGE_SAMPLE_COUNT);
- if (count > 0) {
- pw.print(prefix);
- if (screenStates.length > 1) {
- printScreenLabel(pw, printedScreen != iscreen
- ? iscreen : STATE_NOTHING);
- printedScreen = iscreen;
- }
- if (memStates.length > 1) {
- printMemLabel(pw, printedMem != imem ? imem : STATE_NOTHING, '\0');
- printedMem = imem;
- }
- pw.print(": ");
- pw.print(count);
- pw.println(" samples:");
- dumpSysMemUsageCategory(pw, prefix, " Cached", bucket,
- SYS_MEM_USAGE_CACHED_MINIMUM);
- dumpSysMemUsageCategory(pw, prefix, " Free", bucket,
- SYS_MEM_USAGE_FREE_MINIMUM);
- dumpSysMemUsageCategory(pw, prefix, " ZRam", bucket,
- SYS_MEM_USAGE_ZRAM_MINIMUM);
- dumpSysMemUsageCategory(pw, prefix, " Kernel", bucket,
- SYS_MEM_USAGE_KERNEL_MINIMUM);
- dumpSysMemUsageCategory(pw, prefix, " Native", bucket,
- SYS_MEM_USAGE_NATIVE_MINIMUM);
- }
- }
- }
- }
-
- static void dumpStateHeadersCsv(PrintWriter pw, String sep, int[] screenStates,
- int[] memStates, int[] procStates) {
- final int NS = screenStates != null ? screenStates.length : 1;
- final int NM = memStates != null ? memStates.length : 1;
- final int NP = procStates != null ? procStates.length : 1;
- for (int is=0; is<NS; is++) {
- for (int im=0; im<NM; im++) {
- for (int ip=0; ip<NP; ip++) {
- pw.print(sep);
- boolean printed = false;
- if (screenStates != null && screenStates.length > 1) {
- printScreenLabelCsv(pw, screenStates[is]);
- printed = true;
- }
- if (memStates != null && memStates.length > 1) {
- if (printed) {
- pw.print("-");
- }
- printMemLabelCsv(pw, memStates[im]);
- printed = true;
- }
- if (procStates != null && procStates.length > 1) {
- if (printed) {
- pw.print("-");
- }
- pw.print(STATE_NAMES_CSV[procStates[ip]]);
- }
- }
- }
- }
- }
-
- static void dumpProcessStateCsv(PrintWriter pw, ProcessState proc,
- boolean sepScreenStates, int[] screenStates, boolean sepMemStates, int[] memStates,
- boolean sepProcStates, int[] procStates, long now) {
- final int NSS = sepScreenStates ? screenStates.length : 1;
- final int NMS = sepMemStates ? memStates.length : 1;
- final int NPS = sepProcStates ? procStates.length : 1;
- for (int iss=0; iss<NSS; iss++) {
- for (int ims=0; ims<NMS; ims++) {
- for (int ips=0; ips<NPS; ips++) {
- final int vsscreen = sepScreenStates ? screenStates[iss] : 0;
- final int vsmem = sepMemStates ? memStates[ims] : 0;
- final int vsproc = sepProcStates ? procStates[ips] : 0;
- final int NSA = sepScreenStates ? 1 : screenStates.length;
- final int NMA = sepMemStates ? 1 : memStates.length;
- final int NPA = sepProcStates ? 1 : procStates.length;
- long totalTime = 0;
- for (int isa=0; isa<NSA; isa++) {
- for (int ima=0; ima<NMA; ima++) {
- for (int ipa=0; ipa<NPA; ipa++) {
- final int vascreen = sepScreenStates ? 0 : screenStates[isa];
- final int vamem = sepMemStates ? 0 : memStates[ima];
- final int vaproc = sepProcStates ? 0 : procStates[ipa];
- final int bucket = ((vsscreen + vascreen + vsmem + vamem)
- * STATE_COUNT) + vsproc + vaproc;
- totalTime += proc.getDuration(bucket, now);
- }
- }
- }
- pw.print(CSV_SEP);
- pw.print(totalTime);
- }
- }
- }
- }
-
- static void dumpProcessList(PrintWriter pw, String prefix, ArrayList<ProcessState> procs,
- int[] screenStates, int[] memStates, int[] procStates, long now) {
- String innerPrefix = prefix + " ";
- for (int i=procs.size()-1; i>=0; i--) {
- ProcessState proc = procs.get(i);
- pw.print(prefix);
- pw.print(proc.mName);
- pw.print(" / ");
- UserHandle.formatUid(pw, proc.mUid);
- pw.print(" (");
- pw.print(proc.mDurationsTableSize);
- pw.print(" entries)");
- pw.println(":");
- dumpProcessState(pw, innerPrefix, proc, screenStates, memStates, procStates, now);
- if (proc.mPssTableSize > 0) {
- dumpProcessPss(pw, innerPrefix, proc, screenStates, memStates, procStates);
- }
- }
- }
-
- static void dumpProcessSummaryDetails(PrintWriter pw, ProcessState proc, String prefix,
- String label, int[] screenStates, int[] memStates, int[] procStates,
- long now, long totalTime, boolean full) {
- ProcessDataCollection totals = new ProcessDataCollection(screenStates,
- memStates, procStates);
- computeProcessData(proc, totals, now);
- double percentage = (double) totals.totalTime / (double) totalTime * 100;
- // We don't print percentages < .01, so just drop those.
- if (percentage >= 0.005 || totals.numPss != 0) {
- if (prefix != null) {
- pw.print(prefix);
- }
- if (label != null) {
- pw.print(label);
- }
- totals.print(pw, totalTime, full);
- if (prefix != null) {
- pw.println();
- }
- }
- }
-
- static void dumpProcessSummaryLocked(PrintWriter pw, String prefix,
- ArrayList<ProcessState> procs, int[] screenStates, int[] memStates, int[] procStates,
- boolean inclUidVers, long now, long totalTime) {
- for (int i=procs.size()-1; i>=0; i--) {
- ProcessState proc = procs.get(i);
- pw.print(prefix);
- pw.print("* ");
- pw.print(proc.mName);
- pw.print(" / ");
- UserHandle.formatUid(pw, proc.mUid);
- pw.print(" / v");
- pw.print(proc.mVersion);
- pw.println(":");
- dumpProcessSummaryDetails(pw, proc, prefix, " TOTAL: ", screenStates, memStates,
- procStates, now, totalTime, true);
- dumpProcessSummaryDetails(pw, proc, prefix, " Persistent: ", screenStates, memStates,
- new int[] { STATE_PERSISTENT }, now, totalTime, true);
- dumpProcessSummaryDetails(pw, proc, prefix, " Top: ", screenStates, memStates,
- new int[] {STATE_TOP}, now, totalTime, true);
- dumpProcessSummaryDetails(pw, proc, prefix, " Imp Fg: ", screenStates, memStates,
- new int[] { STATE_IMPORTANT_FOREGROUND }, now, totalTime, true);
- dumpProcessSummaryDetails(pw, proc, prefix, " Imp Bg: ", screenStates, memStates,
- new int[] {STATE_IMPORTANT_BACKGROUND}, now, totalTime, true);
- dumpProcessSummaryDetails(pw, proc, prefix, " Backup: ", screenStates, memStates,
- new int[] {STATE_BACKUP}, now, totalTime, true);
- dumpProcessSummaryDetails(pw, proc, prefix, " Heavy Wgt: ", screenStates, memStates,
- new int[] {STATE_HEAVY_WEIGHT}, now, totalTime, true);
- dumpProcessSummaryDetails(pw, proc, prefix, " Service: ", screenStates, memStates,
- new int[] {STATE_SERVICE}, now, totalTime, true);
- dumpProcessSummaryDetails(pw, proc, prefix, " Service Rs: ", screenStates, memStates,
- new int[] {STATE_SERVICE_RESTARTING}, now, totalTime, true);
- dumpProcessSummaryDetails(pw, proc, prefix, " Receiver: ", screenStates, memStates,
- new int[] {STATE_RECEIVER}, now, totalTime, true);
- dumpProcessSummaryDetails(pw, proc, prefix, " (Home): ", screenStates, memStates,
- new int[] {STATE_HOME}, now, totalTime, true);
- dumpProcessSummaryDetails(pw, proc, prefix, " (Last Act): ", screenStates, memStates,
- new int[] {STATE_LAST_ACTIVITY}, now, totalTime, true);
- dumpProcessSummaryDetails(pw, proc, prefix, " (Cached): ", screenStates, memStates,
- new int[] {STATE_CACHED_ACTIVITY, STATE_CACHED_ACTIVITY_CLIENT,
- STATE_CACHED_EMPTY}, now, totalTime, true);
- }
- }
-
- static void printPercent(PrintWriter pw, double fraction) {
- fraction *= 100;
- if (fraction < 1) {
- pw.print(String.format("%.2f", fraction));
- } else if (fraction < 10) {
- pw.print(String.format("%.1f", fraction));
- } else {
- pw.print(String.format("%.0f", fraction));
- }
- pw.print("%");
- }
-
- public static void dumpProcessListCsv(PrintWriter pw, ArrayList<ProcessState> procs,
- boolean sepScreenStates, int[] screenStates, boolean sepMemStates, int[] memStates,
- boolean sepProcStates, int[] procStates, long now) {
- pw.print("process");
- pw.print(CSV_SEP);
- pw.print("uid");
- pw.print(CSV_SEP);
- pw.print("vers");
- dumpStateHeadersCsv(pw, CSV_SEP, sepScreenStates ? screenStates : null,
- sepMemStates ? memStates : null,
- sepProcStates ? procStates : null);
- pw.println();
- for (int i=procs.size()-1; i>=0; i--) {
- ProcessState proc = procs.get(i);
- pw.print(proc.mName);
- pw.print(CSV_SEP);
- UserHandle.formatUid(pw, proc.mUid);
- pw.print(CSV_SEP);
- pw.print(proc.mVersion);
- dumpProcessStateCsv(pw, proc, sepScreenStates, screenStates,
- sepMemStates, memStates, sepProcStates, procStates, now);
- pw.println();
- }
- }
-
- static int printArrayEntry(PrintWriter pw, String[] array, int value, int mod) {
- int index = value/mod;
- if (index >= 0 && index < array.length) {
- pw.print(array[index]);
- } else {
- pw.print('?');
- }
- return value - index*mod;
- }
-
- static void printProcStateTag(PrintWriter pw, int state) {
- state = printArrayEntry(pw, ADJ_SCREEN_TAGS, state, ADJ_SCREEN_MOD*STATE_COUNT);
- state = printArrayEntry(pw, ADJ_MEM_TAGS, state, STATE_COUNT);
- printArrayEntry(pw, STATE_TAGS, state, 1);
- }
-
- static void printAdjTag(PrintWriter pw, int state) {
- state = printArrayEntry(pw, ADJ_SCREEN_TAGS, state, ADJ_SCREEN_MOD);
- printArrayEntry(pw, ADJ_MEM_TAGS, state, 1);
- }
-
- static void printProcStateTagAndValue(PrintWriter pw, int state, long value) {
- pw.print(',');
- printProcStateTag(pw, state);
- pw.print(':');
- pw.print(value);
- }
-
- static void printAdjTagAndValue(PrintWriter pw, int state, long value) {
- pw.print(',');
- printAdjTag(pw, state);
- pw.print(':');
- pw.print(value);
- }
-
- static void dumpAllProcessStateCheckin(PrintWriter pw, ProcessState proc, long now) {
- boolean didCurState = false;
- for (int i=0; i<proc.mDurationsTableSize; i++) {
- int off = proc.mDurationsTable[i];
- int type = (off>>OFFSET_TYPE_SHIFT)&OFFSET_TYPE_MASK;
- long time = proc.mStats.getLong(off, 0);
- if (proc.mCurState == type) {
- didCurState = true;
- time += now - proc.mStartTime;
- }
- printProcStateTagAndValue(pw, type, time);
- }
- if (!didCurState && proc.mCurState != STATE_NOTHING) {
- printProcStateTagAndValue(pw, proc.mCurState, now - proc.mStartTime);
- }
- }
-
- static void dumpAllProcessPssCheckin(PrintWriter pw, ProcessState proc) {
- for (int i=0; i<proc.mPssTableSize; i++) {
- int off = proc.mPssTable[i];
- int type = (off>>OFFSET_TYPE_SHIFT)&OFFSET_TYPE_MASK;
- long count = proc.mStats.getLong(off, PSS_SAMPLE_COUNT);
- long min = proc.mStats.getLong(off, PSS_MINIMUM);
- long avg = proc.mStats.getLong(off, PSS_AVERAGE);
- long max = proc.mStats.getLong(off, PSS_MAXIMUM);
- long umin = proc.mStats.getLong(off, PSS_USS_MINIMUM);
- long uavg = proc.mStats.getLong(off, PSS_USS_AVERAGE);
- long umax = proc.mStats.getLong(off, PSS_USS_MAXIMUM);
- pw.print(',');
- printProcStateTag(pw, type);
- pw.print(':');
- pw.print(count);
- pw.print(':');
- pw.print(min);
- pw.print(':');
- pw.print(avg);
- pw.print(':');
- pw.print(max);
- pw.print(':');
- pw.print(umin);
- pw.print(':');
- pw.print(uavg);
- pw.print(':');
- pw.print(umax);
- }
- }
-
- public void reset() {
- if (DEBUG) Slog.d(TAG, "Resetting state of " + mTimePeriodStartClockStr);
- resetCommon();
- mPackages.getMap().clear();
- mProcesses.getMap().clear();
- mMemFactor = STATE_NOTHING;
- mStartTime = 0;
- if (DEBUG) Slog.d(TAG, "State reset; now " + mTimePeriodStartClockStr);
- }
-
- public void resetSafely() {
- if (DEBUG) Slog.d(TAG, "Safely resetting state of " + mTimePeriodStartClockStr);
- resetCommon();
-
- // First initialize use count of all common processes.
- final long now = SystemClock.uptimeMillis();
- final ArrayMap<String, SparseArray<ProcessState>> procMap = mProcesses.getMap();
- for (int ip=procMap.size()-1; ip>=0; ip--) {
- final SparseArray<ProcessState> uids = procMap.valueAt(ip);
- for (int iu=uids.size()-1; iu>=0; iu--) {
- uids.valueAt(iu).mTmpNumInUse = 0;
- }
- }
-
- // Next reset or prune all per-package processes, and for the ones that are reset
- // track this back to the common processes.
- final ArrayMap<String, SparseArray<SparseArray<PackageState>>> pkgMap = mPackages.getMap();
- for (int ip=pkgMap.size()-1; ip>=0; ip--) {
- final SparseArray<SparseArray<PackageState>> uids = pkgMap.valueAt(ip);
- for (int iu=uids.size()-1; iu>=0; iu--) {
- final SparseArray<PackageState> vpkgs = uids.valueAt(iu);
- for (int iv=vpkgs.size()-1; iv>=0; iv--) {
- final PackageState pkgState = vpkgs.valueAt(iv);
- for (int iproc=pkgState.mProcesses.size()-1; iproc>=0; iproc--) {
- final ProcessState ps = pkgState.mProcesses.valueAt(iproc);
- if (ps.isInUse()) {
- ps.resetSafely(now);
- ps.mCommonProcess.mTmpNumInUse++;
- ps.mCommonProcess.mTmpFoundSubProc = ps;
- } else {
- pkgState.mProcesses.valueAt(iproc).makeDead();
- pkgState.mProcesses.removeAt(iproc);
- }
- }
- for (int isvc=pkgState.mServices.size()-1; isvc>=0; isvc--) {
- final ServiceState ss = pkgState.mServices.valueAt(isvc);
- if (ss.isInUse()) {
- ss.resetSafely(now);
- } else {
- pkgState.mServices.removeAt(isvc);
- }
- }
- if (pkgState.mProcesses.size() <= 0 && pkgState.mServices.size() <= 0) {
- vpkgs.removeAt(iv);
- }
- }
- if (vpkgs.size() <= 0) {
- uids.removeAt(iu);
- }
- }
- if (uids.size() <= 0) {
- pkgMap.removeAt(ip);
- }
- }
-
- // Finally prune out any common processes that are no longer in use.
- for (int ip=procMap.size()-1; ip>=0; ip--) {
- final SparseArray<ProcessState> uids = procMap.valueAt(ip);
- for (int iu=uids.size()-1; iu>=0; iu--) {
- ProcessState ps = uids.valueAt(iu);
- if (ps.isInUse() || ps.mTmpNumInUse > 0) {
- // If this is a process for multiple packages, we could at this point
- // be back down to one package. In that case, we want to revert back
- // to a single shared ProcessState. We can do this by converting the
- // current package-specific ProcessState up to the shared ProcessState,
- // throwing away the current one we have here (because nobody else is
- // using it).
- if (!ps.mActive && ps.mMultiPackage && ps.mTmpNumInUse == 1) {
- // Here we go...
- ps = ps.mTmpFoundSubProc;
- ps.mCommonProcess = ps;
- uids.setValueAt(iu, ps);
- } else {
- ps.resetSafely(now);
- }
- } else {
- ps.makeDead();
- uids.removeAt(iu);
- }
- }
- if (uids.size() <= 0) {
- procMap.removeAt(ip);
- }
- }
-
- mStartTime = now;
- if (DEBUG) Slog.d(TAG, "State reset; now " + mTimePeriodStartClockStr);
- }
-
- private void resetCommon() {
- mTimePeriodStartClock = System.currentTimeMillis();
- buildTimePeriodStartClockStr();
- mTimePeriodStartRealtime = mTimePeriodEndRealtime = SystemClock.elapsedRealtime();
- mTimePeriodStartUptime = mTimePeriodEndUptime = SystemClock.uptimeMillis();
- mLongs.clear();
- mLongs.add(new long[LONGS_SIZE]);
- mNextLong = 0;
- Arrays.fill(mMemFactorDurations, 0);
- mSysMemUsageTable = null;
- mSysMemUsageTableSize = 0;
- mStartTime = 0;
- mReadError = null;
- mFlags = 0;
- evaluateSystemProperties(true);
- }
-
- public boolean evaluateSystemProperties(boolean update) {
- boolean changed = false;
- String runtime = SystemProperties.get("persist.sys.dalvik.vm.lib.2",
- VMRuntime.getRuntime().vmLibrary());
- if (!Objects.equals(runtime, mRuntime)) {
- changed = true;
- if (update) {
- mRuntime = runtime;
- }
- }
- return changed;
- }
-
- private void buildTimePeriodStartClockStr() {
- mTimePeriodStartClockStr = DateFormat.format("yyyy-MM-dd-HH-mm-ss",
- mTimePeriodStartClock).toString();
- }
-
- static final int[] BAD_TABLE = new int[0];
-
- private int[] readTableFromParcel(Parcel in, String name, String what) {
- final int size = in.readInt();
- if (size < 0) {
- Slog.w(TAG, "Ignoring existing stats; bad " + what + " table size: " + size);
- return BAD_TABLE;
- }
- if (size == 0) {
- return null;
- }
- final int[] table = new int[size];
- for (int i=0; i<size; i++) {
- table[i] = in.readInt();
- if (DEBUG_PARCEL) Slog.i(TAG, "Reading in " + name + " table #" + i + ": "
- + ProcessStats.printLongOffset(table[i]));
- if (!validateLongOffset(table[i])) {
- Slog.w(TAG, "Ignoring existing stats; bad " + what + " table entry: "
- + ProcessStats.printLongOffset(table[i]));
- return null;
- }
- }
- return table;
- }
-
- private void writeCompactedLongArray(Parcel out, long[] array, int num) {
- for (int i=0; i<num; i++) {
- long val = array[i];
- if (val < 0) {
- Slog.w(TAG, "Time val negative: " + val);
- val = 0;
- }
- if (val <= Integer.MAX_VALUE) {
- out.writeInt((int)val);
- } else {
- int top = ~((int)((val>>32)&0x7fffffff));
- int bottom = (int)(val&0xfffffff);
- out.writeInt(top);
- out.writeInt(bottom);
- }
- }
- }
-
- private void readCompactedLongArray(Parcel in, int version, long[] array, int num) {
- if (version <= 10) {
- in.readLongArray(array);
- return;
- }
- final int alen = array.length;
- if (num > alen) {
- throw new RuntimeException("bad array lengths: got " + num + " array is " + alen);
- }
- int i;
- for (i=0; i<num; i++) {
- int val = in.readInt();
- if (val >= 0) {
- array[i] = val;
- } else {
- int bottom = in.readInt();
- array[i] = (((long)~val)<<32) | bottom;
- }
- }
- while (i < alen) {
- array[i] = 0;
- i++;
- }
- }
-
- private void writeCommonString(Parcel out, String name) {
- Integer index = mCommonStringToIndex.get(name);
- if (index != null) {
- out.writeInt(index);
- return;
- }
- index = mCommonStringToIndex.size();
- mCommonStringToIndex.put(name, index);
- out.writeInt(~index);
- out.writeString(name);
- }
-
- private String readCommonString(Parcel in, int version) {
- if (version <= 9) {
- return in.readString();
- }
- int index = in.readInt();
- if (index >= 0) {
- return mIndexToCommonString.get(index);
- }
- index = ~index;
- String name = in.readString();
- while (mIndexToCommonString.size() <= index) {
- mIndexToCommonString.add(null);
- }
- mIndexToCommonString.set(index, name);
- return name;
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(Parcel out, int flags) {
- writeToParcel(out, SystemClock.uptimeMillis(), flags);
- }
-
- /** @hide */
- public void writeToParcel(Parcel out, long now, int flags) {
- out.writeInt(MAGIC);
- out.writeInt(PARCEL_VERSION);
- out.writeInt(STATE_COUNT);
- out.writeInt(ADJ_COUNT);
- out.writeInt(PSS_COUNT);
- out.writeInt(SYS_MEM_USAGE_COUNT);
- out.writeInt(LONGS_SIZE);
-
- mCommonStringToIndex = new ArrayMap<String, Integer>(mProcesses.mMap.size());
-
- // First commit all running times.
- ArrayMap<String, SparseArray<ProcessState>> procMap = mProcesses.getMap();
- final int NPROC = procMap.size();
- for (int ip=0; ip<NPROC; ip++) {
- SparseArray<ProcessState> uids = procMap.valueAt(ip);
- final int NUID = uids.size();
- for (int iu=0; iu<NUID; iu++) {
- uids.valueAt(iu).commitStateTime(now);
- }
- }
- final ArrayMap<String, SparseArray<SparseArray<PackageState>>> pkgMap = mPackages.getMap();
- final int NPKG = pkgMap.size();
- for (int ip=0; ip<NPKG; ip++) {
- final SparseArray<SparseArray<PackageState>> uids = pkgMap.valueAt(ip);
- final int NUID = uids.size();
- for (int iu=0; iu<NUID; iu++) {
- final SparseArray<PackageState> vpkgs = uids.valueAt(iu);
- final int NVERS = vpkgs.size();
- for (int iv=0; iv<NVERS; iv++) {
- PackageState pkgState = vpkgs.valueAt(iv);
- final int NPROCS = pkgState.mProcesses.size();
- for (int iproc=0; iproc<NPROCS; iproc++) {
- ProcessState proc = pkgState.mProcesses.valueAt(iproc);
- if (proc.mCommonProcess != proc) {
- proc.commitStateTime(now);
- }
- }
- final int NSRVS = pkgState.mServices.size();
- for (int isvc=0; isvc<NSRVS; isvc++) {
- pkgState.mServices.valueAt(isvc).commitStateTime(now);
- }
- }
- }
- }
-
- out.writeLong(mTimePeriodStartClock);
- out.writeLong(mTimePeriodStartRealtime);
- out.writeLong(mTimePeriodEndRealtime);
- out.writeLong(mTimePeriodStartUptime);
- out.writeLong(mTimePeriodEndUptime);
- out.writeString(mRuntime);
- out.writeInt(mFlags);
-
- out.writeInt(mLongs.size());
- out.writeInt(mNextLong);
- for (int i=0; i<(mLongs.size()-1); i++) {
- long[] array = mLongs.get(i);
- writeCompactedLongArray(out, array, array.length);
- }
- long[] lastLongs = mLongs.get(mLongs.size() - 1);
- writeCompactedLongArray(out, lastLongs, mNextLong);
-
- if (mMemFactor != STATE_NOTHING) {
- mMemFactorDurations[mMemFactor] += now - mStartTime;
- mStartTime = now;
- }
- writeCompactedLongArray(out, mMemFactorDurations, mMemFactorDurations.length);
-
- out.writeInt(mSysMemUsageTableSize);
- for (int i=0; i<mSysMemUsageTableSize; i++) {
- if (DEBUG_PARCEL) Slog.i(TAG, "Writing sys mem usage #" + i + ": "
- + printLongOffset(mSysMemUsageTable[i]));
- out.writeInt(mSysMemUsageTable[i]);
- }
-
- out.writeInt(NPROC);
- for (int ip=0; ip<NPROC; ip++) {
- writeCommonString(out, procMap.keyAt(ip));
- final SparseArray<ProcessState> uids = procMap.valueAt(ip);
- final int NUID = uids.size();
- out.writeInt(NUID);
- for (int iu=0; iu<NUID; iu++) {
- out.writeInt(uids.keyAt(iu));
- final ProcessState proc = uids.valueAt(iu);
- writeCommonString(out, proc.mPackage);
- out.writeInt(proc.mVersion);
- proc.writeToParcel(out, now);
- }
- }
- out.writeInt(NPKG);
- for (int ip=0; ip<NPKG; ip++) {
- writeCommonString(out, pkgMap.keyAt(ip));
- final SparseArray<SparseArray<PackageState>> uids = pkgMap.valueAt(ip);
- final int NUID = uids.size();
- out.writeInt(NUID);
- for (int iu=0; iu<NUID; iu++) {
- out.writeInt(uids.keyAt(iu));
- final SparseArray<PackageState> vpkgs = uids.valueAt(iu);
- final int NVERS = vpkgs.size();
- out.writeInt(NVERS);
- for (int iv=0; iv<NVERS; iv++) {
- out.writeInt(vpkgs.keyAt(iv));
- final PackageState pkgState = vpkgs.valueAt(iv);
- final int NPROCS = pkgState.mProcesses.size();
- out.writeInt(NPROCS);
- for (int iproc=0; iproc<NPROCS; iproc++) {
- writeCommonString(out, pkgState.mProcesses.keyAt(iproc));
- final ProcessState proc = pkgState.mProcesses.valueAt(iproc);
- if (proc.mCommonProcess == proc) {
- // This is the same as the common process we wrote above.
- out.writeInt(0);
- } else {
- // There is separate data for this package's process.
- out.writeInt(1);
- proc.writeToParcel(out, now);
- }
- }
- final int NSRVS = pkgState.mServices.size();
- out.writeInt(NSRVS);
- for (int isvc=0; isvc<NSRVS; isvc++) {
- out.writeString(pkgState.mServices.keyAt(isvc));
- final ServiceState svc = pkgState.mServices.valueAt(isvc);
- writeCommonString(out, svc.mProcessName);
- svc.writeToParcel(out, now);
- }
- }
- }
- }
-
- mCommonStringToIndex = null;
- }
-
- private boolean readCheckedInt(Parcel in, int val, String what) {
- int got;
- if ((got=in.readInt()) != val) {
- mReadError = "bad " + what + ": " + got;
- return false;
- }
- return true;
- }
-
- static byte[] readFully(InputStream stream, int[] outLen) throws IOException {
- int pos = 0;
- final int initialAvail = stream.available();
- byte[] data = new byte[initialAvail > 0 ? (initialAvail+1) : 16384];
- while (true) {
- int amt = stream.read(data, pos, data.length-pos);
- if (DEBUG_PARCEL) Slog.i("foo", "Read " + amt + " bytes at " + pos
- + " of avail " + data.length);
- if (amt < 0) {
- if (DEBUG_PARCEL) Slog.i("foo", "**** FINISHED READING: pos=" + pos
- + " len=" + data.length);
- outLen[0] = pos;
- return data;
- }
- pos += amt;
- if (pos >= data.length) {
- byte[] newData = new byte[pos+16384];
- if (DEBUG_PARCEL) Slog.i(TAG, "Copying " + pos + " bytes to new array len "
- + newData.length);
- System.arraycopy(data, 0, newData, 0, pos);
- data = newData;
- }
- }
- }
-
- public void read(InputStream stream) {
- try {
- int[] len = new int[1];
- byte[] raw = readFully(stream, len);
- Parcel in = Parcel.obtain();
- in.unmarshall(raw, 0, len[0]);
- in.setDataPosition(0);
- stream.close();
-
- readFromParcel(in);
- } catch (IOException e) {
- mReadError = "caught exception: " + e;
- }
- }
-
- public void readFromParcel(Parcel in) {
- final boolean hadData = mPackages.getMap().size() > 0
- || mProcesses.getMap().size() > 0;
- if (hadData) {
- resetSafely();
- }
-
- if (!readCheckedInt(in, MAGIC, "magic number")) {
- return;
- }
- int version = in.readInt();
- if (version != PARCEL_VERSION) {
- mReadError = "bad version: " + version;
- return;
- }
- if (!readCheckedInt(in, STATE_COUNT, "state count")) {
- return;
- }
- if (!readCheckedInt(in, ADJ_COUNT, "adj count")) {
- return;
- }
- if (!readCheckedInt(in, PSS_COUNT, "pss count")) {
- return;
- }
- if (!readCheckedInt(in, SYS_MEM_USAGE_COUNT, "sys mem usage count")) {
- return;
- }
- if (!readCheckedInt(in, LONGS_SIZE, "longs size")) {
- return;
- }
-
- mIndexToCommonString = new ArrayList<String>();
-
- mTimePeriodStartClock = in.readLong();
- buildTimePeriodStartClockStr();
- mTimePeriodStartRealtime = in.readLong();
- mTimePeriodEndRealtime = in.readLong();
- mTimePeriodStartUptime = in.readLong();
- mTimePeriodEndUptime = in.readLong();
- mRuntime = in.readString();
- mFlags = in.readInt();
-
- final int NLONGS = in.readInt();
- final int NEXTLONG = in.readInt();
- mLongs.clear();
- for (int i=0; i<(NLONGS-1); i++) {
- while (i >= mLongs.size()) {
- mLongs.add(new long[LONGS_SIZE]);
- }
- readCompactedLongArray(in, version, mLongs.get(i), LONGS_SIZE);
- }
- long[] longs = new long[LONGS_SIZE];
- mNextLong = NEXTLONG;
- readCompactedLongArray(in, version, longs, NEXTLONG);
- mLongs.add(longs);
-
- readCompactedLongArray(in, version, mMemFactorDurations, mMemFactorDurations.length);
-
- mSysMemUsageTable = readTableFromParcel(in, TAG, "sys mem usage");
- if (mSysMemUsageTable == BAD_TABLE) {
- return;
- }
- mSysMemUsageTableSize = mSysMemUsageTable != null ? mSysMemUsageTable.length : 0;
-
- int NPROC = in.readInt();
- if (NPROC < 0) {
- mReadError = "bad process count: " + NPROC;
- return;
- }
- while (NPROC > 0) {
- NPROC--;
- final String procName = readCommonString(in, version);
- if (procName == null) {
- mReadError = "bad process name";
- return;
- }
- int NUID = in.readInt();
- if (NUID < 0) {
- mReadError = "bad uid count: " + NUID;
- return;
- }
- while (NUID > 0) {
- NUID--;
- final int uid = in.readInt();
- if (uid < 0) {
- mReadError = "bad uid: " + uid;
- return;
- }
- final String pkgName = readCommonString(in, version);
- if (pkgName == null) {
- mReadError = "bad process package name";
- return;
- }
- final int vers = in.readInt();
- ProcessState proc = hadData ? mProcesses.get(procName, uid) : null;
- if (proc != null) {
- if (!proc.readFromParcel(in, false)) {
- return;
- }
- } else {
- proc = new ProcessState(this, pkgName, uid, vers, procName);
- if (!proc.readFromParcel(in, true)) {
- return;
- }
- }
- if (DEBUG_PARCEL) Slog.d(TAG, "Adding process: " + procName + " " + uid
- + " " + proc);
- mProcesses.put(procName, uid, proc);
- }
- }
-
- if (DEBUG_PARCEL) Slog.d(TAG, "Read " + mProcesses.getMap().size() + " processes");
-
- int NPKG = in.readInt();
- if (NPKG < 0) {
- mReadError = "bad package count: " + NPKG;
- return;
- }
- while (NPKG > 0) {
- NPKG--;
- final String pkgName = readCommonString(in, version);
- if (pkgName == null) {
- mReadError = "bad package name";
- return;
- }
- int NUID = in.readInt();
- if (NUID < 0) {
- mReadError = "bad uid count: " + NUID;
- return;
- }
- while (NUID > 0) {
- NUID--;
- final int uid = in.readInt();
- if (uid < 0) {
- mReadError = "bad uid: " + uid;
- return;
- }
- int NVERS = in.readInt();
- if (NVERS < 0) {
- mReadError = "bad versions count: " + NVERS;
- return;
- }
- while (NVERS > 0) {
- NVERS--;
- final int vers = in.readInt();
- PackageState pkgState = new PackageState(pkgName, uid);
- SparseArray<PackageState> vpkg = mPackages.get(pkgName, uid);
- if (vpkg == null) {
- vpkg = new SparseArray<PackageState>();
- mPackages.put(pkgName, uid, vpkg);
- }
- vpkg.put(vers, pkgState);
- int NPROCS = in.readInt();
- if (NPROCS < 0) {
- mReadError = "bad package process count: " + NPROCS;
- return;
- }
- while (NPROCS > 0) {
- NPROCS--;
- String procName = readCommonString(in, version);
- if (procName == null) {
- mReadError = "bad package process name";
- return;
- }
- int hasProc = in.readInt();
- if (DEBUG_PARCEL) Slog.d(TAG, "Reading package " + pkgName + " " + uid
- + " process " + procName + " hasProc=" + hasProc);
- ProcessState commonProc = mProcesses.get(procName, uid);
- if (DEBUG_PARCEL) Slog.d(TAG, "Got common proc " + procName + " " + uid
- + ": " + commonProc);
- if (commonProc == null) {
- mReadError = "no common proc: " + procName;
- return;
- }
- if (hasProc != 0) {
- // The process for this package is unique to the package; we
- // need to load it. We don't need to do anything about it if
- // it is not unique because if someone later looks for it
- // they will find and use it from the global procs.
- ProcessState proc = hadData ? pkgState.mProcesses.get(procName) : null;
- if (proc != null) {
- if (!proc.readFromParcel(in, false)) {
- return;
- }
- } else {
- proc = new ProcessState(commonProc, pkgName, uid, vers, procName,
- 0);
- if (!proc.readFromParcel(in, true)) {
- return;
- }
- }
- if (DEBUG_PARCEL) Slog.d(TAG, "Adding package " + pkgName + " process: "
- + procName + " " + uid + " " + proc);
- pkgState.mProcesses.put(procName, proc);
- } else {
- if (DEBUG_PARCEL) Slog.d(TAG, "Adding package " + pkgName + " process: "
- + procName + " " + uid + " " + commonProc);
- pkgState.mProcesses.put(procName, commonProc);
- }
- }
- int NSRVS = in.readInt();
- if (NSRVS < 0) {
- mReadError = "bad package service count: " + NSRVS;
- return;
- }
- while (NSRVS > 0) {
- NSRVS--;
- String serviceName = in.readString();
- if (serviceName == null) {
- mReadError = "bad package service name";
- return;
- }
- String processName = version > 9 ? readCommonString(in, version) : null;
- ServiceState serv = hadData ? pkgState.mServices.get(serviceName) : null;
- if (serv == null) {
- serv = new ServiceState(this, pkgName, serviceName, processName, null);
- }
- if (!serv.readFromParcel(in)) {
- return;
- }
- if (DEBUG_PARCEL) Slog.d(TAG, "Adding package " + pkgName + " service: "
- + serviceName + " " + uid + " " + serv);
- pkgState.mServices.put(serviceName, serv);
- }
- }
- }
- }
-
- mIndexToCommonString = null;
-
- if (DEBUG_PARCEL) Slog.d(TAG, "Successfully read procstats!");
- }
-
- int addLongData(int index, int type, int num) {
- int off = allocLongData(num);
- mAddLongTable = GrowingArrayUtils.insert(
- mAddLongTable != null ? mAddLongTable : EmptyArray.INT,
- mAddLongTableSize, index, type | off);
- mAddLongTableSize++;
- return off;
- }
-
- int allocLongData(int num) {
- int whichLongs = mLongs.size()-1;
- long[] longs = mLongs.get(whichLongs);
- if (mNextLong + num > longs.length) {
- longs = new long[LONGS_SIZE];
- mLongs.add(longs);
- whichLongs++;
- mNextLong = 0;
- }
- int off = (whichLongs<<OFFSET_ARRAY_SHIFT) | (mNextLong<<OFFSET_INDEX_SHIFT);
- mNextLong += num;
- return off;
- }
-
- boolean validateLongOffset(int off) {
- int arr = (off>>OFFSET_ARRAY_SHIFT)&OFFSET_ARRAY_MASK;
- if (arr >= mLongs.size()) {
- return false;
- }
- int idx = (off>>OFFSET_INDEX_SHIFT)&OFFSET_INDEX_MASK;
- if (idx >= LONGS_SIZE) {
- return false;
- }
- if (DEBUG_PARCEL) Slog.d(TAG, "Validated long " + printLongOffset(off)
- + ": " + getLong(off, 0));
- return true;
- }
-
- static String printLongOffset(int off) {
- StringBuilder sb = new StringBuilder(16);
- sb.append("a"); sb.append((off>>OFFSET_ARRAY_SHIFT)&OFFSET_ARRAY_MASK);
- sb.append("i"); sb.append((off>>OFFSET_INDEX_SHIFT)&OFFSET_INDEX_MASK);
- sb.append("t"); sb.append((off>>OFFSET_TYPE_SHIFT)&OFFSET_TYPE_MASK);
- return sb.toString();
- }
-
- void setLong(int off, int index, long value) {
- long[] longs = mLongs.get((off>>OFFSET_ARRAY_SHIFT)&OFFSET_ARRAY_MASK);
- longs[index + ((off>>OFFSET_INDEX_SHIFT)&OFFSET_INDEX_MASK)] = value;
- }
-
- long getLong(int off, int index) {
- long[] longs = mLongs.get((off>>OFFSET_ARRAY_SHIFT)&OFFSET_ARRAY_MASK);
- return longs[index + ((off>>OFFSET_INDEX_SHIFT)&OFFSET_INDEX_MASK)];
- }
-
- static int binarySearch(int[] array, int size, int value) {
- int lo = 0;
- int hi = size - 1;
-
- while (lo <= hi) {
- int mid = (lo + hi) >>> 1;
- int midVal = (array[mid] >> OFFSET_TYPE_SHIFT) & OFFSET_TYPE_MASK;
-
- if (midVal < value) {
- lo = mid + 1;
- } else if (midVal > value) {
- hi = mid - 1;
- } else {
- return mid; // value found
- }
- }
- return ~lo; // value not present
- }
-
- public PackageState getPackageStateLocked(String packageName, int uid, int vers) {
- SparseArray<PackageState> vpkg = mPackages.get(packageName, uid);
- if (vpkg == null) {
- vpkg = new SparseArray<PackageState>();
- mPackages.put(packageName, uid, vpkg);
- }
- PackageState as = vpkg.get(vers);
- if (as != null) {
- return as;
- }
- as = new PackageState(packageName, uid);
- vpkg.put(vers, as);
- return as;
- }
-
- public ProcessState getProcessStateLocked(String packageName, int uid, int vers,
- String processName) {
- final PackageState pkgState = getPackageStateLocked(packageName, uid, vers);
- ProcessState ps = pkgState.mProcesses.get(processName);
- if (ps != null) {
- return ps;
- }
- ProcessState commonProc = mProcesses.get(processName, uid);
- if (commonProc == null) {
- commonProc = new ProcessState(this, packageName, uid, vers, processName);
- mProcesses.put(processName, uid, commonProc);
- if (DEBUG) Slog.d(TAG, "GETPROC created new common " + commonProc);
- }
- if (!commonProc.mMultiPackage) {
- if (packageName.equals(commonProc.mPackage) && vers == commonProc.mVersion) {
- // This common process is not in use by multiple packages, and
- // is for the calling package, so we can just use it directly.
- ps = commonProc;
- if (DEBUG) Slog.d(TAG, "GETPROC also using for pkg " + commonProc);
- } else {
- if (DEBUG) Slog.d(TAG, "GETPROC need to split common proc!");
- // This common process has not been in use by multiple packages,
- // but it was created for a different package than the caller.
- // We need to convert it to a multi-package process.
- commonProc.mMultiPackage = true;
- // To do this, we need to make two new process states, one a copy
- // of the current state for the process under the original package
- // name, and the second a free new process state for it as the
- // new package name.
- long now = SystemClock.uptimeMillis();
- // First let's make a copy of the current process state and put
- // that under the now unique state for its original package name.
- final PackageState commonPkgState = getPackageStateLocked(commonProc.mPackage,
- uid, commonProc.mVersion);
- if (commonPkgState != null) {
- ProcessState cloned = commonProc.clone(commonProc.mPackage, now);
- if (DEBUG) Slog.d(TAG, "GETPROC setting clone to pkg " + commonProc.mPackage
- + ": " + cloned);
- commonPkgState.mProcesses.put(commonProc.mName, cloned);
- // If this has active services, we need to update their process pointer
- // to point to the new package-specific process state.
- for (int i=commonPkgState.mServices.size()-1; i>=0; i--) {
- ServiceState ss = commonPkgState.mServices.valueAt(i);
- if (ss.mProc == commonProc) {
- if (DEBUG) Slog.d(TAG, "GETPROC switching service to cloned: "
- + ss);
- ss.mProc = cloned;
- } else if (DEBUG) {
- Slog.d(TAG, "GETPROC leaving proc of " + ss);
- }
- }
- } else {
- Slog.w(TAG, "Cloning proc state: no package state " + commonProc.mPackage
- + "/" + uid + " for proc " + commonProc.mName);
- }
- // And now make a fresh new process state for the new package name.
- ps = new ProcessState(commonProc, packageName, uid, vers, processName, now);
- if (DEBUG) Slog.d(TAG, "GETPROC created new pkg " + ps);
- }
- } else {
- // The common process is for multiple packages, we need to create a
- // separate object for the per-package data.
- ps = new ProcessState(commonProc, packageName, uid, vers, processName,
- SystemClock.uptimeMillis());
- if (DEBUG) Slog.d(TAG, "GETPROC created new pkg " + ps);
- }
- pkgState.mProcesses.put(processName, ps);
- if (DEBUG) Slog.d(TAG, "GETPROC adding new pkg " + ps);
- return ps;
- }
-
- public ProcessStats.ServiceState getServiceStateLocked(String packageName, int uid, int vers,
- String processName, String className) {
- final ProcessStats.PackageState as = getPackageStateLocked(packageName, uid, vers);
- ProcessStats.ServiceState ss = as.mServices.get(className);
- if (ss != null) {
- if (DEBUG) Slog.d(TAG, "GETSVC: returning existing " + ss);
- return ss;
- }
- final ProcessStats.ProcessState ps = processName != null
- ? getProcessStateLocked(packageName, uid, vers, processName) : null;
- ss = new ProcessStats.ServiceState(this, packageName, className, processName, ps);
- as.mServices.put(className, ss);
- if (DEBUG) Slog.d(TAG, "GETSVC: creating " + ss + " in " + ps);
- return ss;
- }
-
- private void dumpProcessInternalLocked(PrintWriter pw, String prefix, ProcessState proc,
- boolean dumpAll) {
- if (dumpAll) {
- pw.print(prefix); pw.print("myID=");
- pw.print(Integer.toHexString(System.identityHashCode(proc)));
- pw.print(" mCommonProcess=");
- pw.print(Integer.toHexString(System.identityHashCode(proc.mCommonProcess)));
- pw.print(" mPackage="); pw.println(proc.mPackage);
- if (proc.mMultiPackage) {
- pw.print(prefix); pw.print("mMultiPackage="); pw.println(proc.mMultiPackage);
- }
- if (proc != proc.mCommonProcess) {
- pw.print(prefix); pw.print("Common Proc: "); pw.print(proc.mCommonProcess.mName);
- pw.print("/"); pw.print(proc.mCommonProcess.mUid);
- pw.print(" pkg="); pw.println(proc.mCommonProcess.mPackage);
- }
- }
- if (proc.mActive) {
- pw.print(prefix); pw.print("mActive="); pw.println(proc.mActive);
- }
- if (proc.mDead) {
- pw.print(prefix); pw.print("mDead="); pw.println(proc.mDead);
- }
- if (proc.mNumActiveServices != 0 || proc.mNumStartedServices != 0) {
- pw.print(prefix); pw.print("mNumActiveServices="); pw.print(proc.mNumActiveServices);
- pw.print(" mNumStartedServices=");
- pw.println(proc.mNumStartedServices);
- }
- }
-
- public void dumpLocked(PrintWriter pw, String reqPackage, long now, boolean dumpSummary,
- boolean dumpAll, boolean activeOnly) {
- long totalTime = dumpSingleTime(null, null, mMemFactorDurations, mMemFactor,
- mStartTime, now);
- boolean sepNeeded = false;
- if (mSysMemUsageTable != null) {
- pw.println("System memory usage:");
- dumpSysMemUsage(pw, " ", ALL_SCREEN_ADJ, ALL_MEM_ADJ);
- sepNeeded = true;
- }
- ArrayMap<String, SparseArray<SparseArray<PackageState>>> pkgMap = mPackages.getMap();
- boolean printedHeader = false;
- for (int ip=0; ip<pkgMap.size(); ip++) {
- final String pkgName = pkgMap.keyAt(ip);
- final SparseArray<SparseArray<PackageState>> uids = pkgMap.valueAt(ip);
- for (int iu=0; iu<uids.size(); iu++) {
- final int uid = uids.keyAt(iu);
- final SparseArray<PackageState> vpkgs = uids.valueAt(iu);
- for (int iv=0; iv<vpkgs.size(); iv++) {
- final int vers = vpkgs.keyAt(iv);
- final PackageState pkgState = vpkgs.valueAt(iv);
- final int NPROCS = pkgState.mProcesses.size();
- final int NSRVS = pkgState.mServices.size();
- final boolean pkgMatch = reqPackage == null || reqPackage.equals(pkgName);
- if (!pkgMatch) {
- boolean procMatch = false;
- for (int iproc=0; iproc<NPROCS; iproc++) {
- ProcessState proc = pkgState.mProcesses.valueAt(iproc);
- if (reqPackage.equals(proc.mName)) {
- procMatch = true;
- break;
- }
- }
- if (!procMatch) {
- continue;
- }
- }
- if (NPROCS > 0 || NSRVS > 0) {
- if (!printedHeader) {
- if (sepNeeded) pw.println();
- pw.println("Per-Package Stats:");
- printedHeader = true;
- sepNeeded = true;
- }
- pw.print(" * "); pw.print(pkgName); pw.print(" / ");
- UserHandle.formatUid(pw, uid); pw.print(" / v");
- pw.print(vers); pw.println(":");
- }
- if (!dumpSummary || dumpAll) {
- for (int iproc=0; iproc<NPROCS; iproc++) {
- ProcessState proc = pkgState.mProcesses.valueAt(iproc);
- if (!pkgMatch && !reqPackage.equals(proc.mName)) {
- continue;
- }
- if (activeOnly && !proc.isInUse()) {
- pw.print(" (Not active: ");
- pw.print(pkgState.mProcesses.keyAt(iproc)); pw.println(")");
- continue;
- }
- pw.print(" Process ");
- pw.print(pkgState.mProcesses.keyAt(iproc));
- if (proc.mCommonProcess.mMultiPackage) {
- pw.print(" (multi, ");
- } else {
- pw.print(" (unique, ");
- }
- pw.print(proc.mDurationsTableSize);
- pw.print(" entries)");
- pw.println(":");
- dumpProcessState(pw, " ", proc, ALL_SCREEN_ADJ, ALL_MEM_ADJ,
- ALL_PROC_STATES, now);
- dumpProcessPss(pw, " ", proc, ALL_SCREEN_ADJ, ALL_MEM_ADJ,
- ALL_PROC_STATES);
- dumpProcessInternalLocked(pw, " ", proc, dumpAll);
- }
- } else {
- ArrayList<ProcessState> procs = new ArrayList<ProcessState>();
- for (int iproc=0; iproc<NPROCS; iproc++) {
- ProcessState proc = pkgState.mProcesses.valueAt(iproc);
- if (!pkgMatch && !reqPackage.equals(proc.mName)) {
- continue;
- }
- if (activeOnly && !proc.isInUse()) {
- continue;
- }
- procs.add(proc);
- }
- dumpProcessSummaryLocked(pw, " ", procs, ALL_SCREEN_ADJ, ALL_MEM_ADJ,
- NON_CACHED_PROC_STATES, false, now, totalTime);
- }
- for (int isvc=0; isvc<NSRVS; isvc++) {
- ServiceState svc = pkgState.mServices.valueAt(isvc);
- if (!pkgMatch && !reqPackage.equals(svc.mProcessName)) {
- continue;
- }
- if (activeOnly && !svc.isInUse()) {
- pw.print(" (Not active: ");
- pw.print(pkgState.mServices.keyAt(isvc)); pw.println(")");
- continue;
- }
- if (dumpAll) {
- pw.print(" Service ");
- } else {
- pw.print(" * ");
- }
- pw.print(pkgState.mServices.keyAt(isvc));
- pw.println(":");
- pw.print(" Process: "); pw.println(svc.mProcessName);
- dumpServiceStats(pw, " ", " ", " ", "Running", svc,
- svc.mRunCount, ServiceState.SERVICE_RUN, svc.mRunState,
- svc.mRunStartTime, now, totalTime, !dumpSummary || dumpAll);
- dumpServiceStats(pw, " ", " ", " ", "Started", svc,
- svc.mStartedCount, ServiceState.SERVICE_STARTED, svc.mStartedState,
- svc.mStartedStartTime, now, totalTime, !dumpSummary || dumpAll);
- dumpServiceStats(pw, " ", " ", " ", "Bound", svc,
- svc.mBoundCount, ServiceState.SERVICE_BOUND, svc.mBoundState,
- svc.mBoundStartTime, now, totalTime, !dumpSummary || dumpAll);
- dumpServiceStats(pw, " ", " ", " ", "Executing", svc,
- svc.mExecCount, ServiceState.SERVICE_EXEC, svc.mExecState,
- svc.mExecStartTime, now, totalTime, !dumpSummary || dumpAll);
- if (dumpAll) {
- if (svc.mOwner != null) {
- pw.print(" mOwner="); pw.println(svc.mOwner);
- }
- if (svc.mStarted || svc.mRestarting) {
- pw.print(" mStarted="); pw.print(svc.mStarted);
- pw.print(" mRestarting="); pw.println(svc.mRestarting);
- }
- }
- }
- }
- }
- }
-
- ArrayMap<String, SparseArray<ProcessState>> procMap = mProcesses.getMap();
- printedHeader = false;
- int numShownProcs = 0, numTotalProcs = 0;
- for (int ip=0; ip<procMap.size(); ip++) {
- String procName = procMap.keyAt(ip);
- SparseArray<ProcessState> uids = procMap.valueAt(ip);
- for (int iu=0; iu<uids.size(); iu++) {
- int uid = uids.keyAt(iu);
- numTotalProcs++;
- ProcessState proc = uids.valueAt(iu);
- if (proc.mDurationsTableSize == 0 && proc.mCurState == STATE_NOTHING
- && proc.mPssTableSize == 0) {
- continue;
- }
- if (!proc.mMultiPackage) {
- continue;
- }
- if (reqPackage != null && !reqPackage.equals(procName)
- && !reqPackage.equals(proc.mPackage)) {
- continue;
- }
- numShownProcs++;
- if (sepNeeded) {
- pw.println();
- }
- sepNeeded = true;
- if (!printedHeader) {
- pw.println("Multi-Package Common Processes:");
- printedHeader = true;
- }
- if (activeOnly && !proc.isInUse()) {
- pw.print(" (Not active: "); pw.print(procName); pw.println(")");
- continue;
- }
- pw.print(" * "); pw.print(procName); pw.print(" / ");
- UserHandle.formatUid(pw, uid);
- pw.print(" ("); pw.print(proc.mDurationsTableSize);
- pw.print(" entries)"); pw.println(":");
- dumpProcessState(pw, " ", proc, ALL_SCREEN_ADJ, ALL_MEM_ADJ,
- ALL_PROC_STATES, now);
- dumpProcessPss(pw, " ", proc, ALL_SCREEN_ADJ, ALL_MEM_ADJ,
- ALL_PROC_STATES);
- dumpProcessInternalLocked(pw, " ", proc, dumpAll);
- }
- }
- if (dumpAll) {
- pw.println();
- pw.print(" Total procs: "); pw.print(numShownProcs);
- pw.print(" shown of "); pw.print(numTotalProcs); pw.println(" total");
- }
-
- if (sepNeeded) {
- pw.println();
- }
- if (dumpSummary) {
- pw.println("Summary:");
- dumpSummaryLocked(pw, reqPackage, now, activeOnly);
- } else {
- dumpTotalsLocked(pw, now);
- }
-
- if (dumpAll) {
- pw.println();
- pw.println("Internal state:");
- pw.print(" Num long arrays: "); pw.println(mLongs.size());
- pw.print(" Next long entry: "); pw.println(mNextLong);
- pw.print(" mRunning="); pw.println(mRunning);
- }
- }
-
- public static long dumpSingleServiceTime(PrintWriter pw, String prefix, ServiceState service,
- int serviceType, int curState, long curStartTime, long now) {
- long totalTime = 0;
- int printedScreen = -1;
- for (int iscreen=0; iscreen<ADJ_COUNT; iscreen+=ADJ_SCREEN_MOD) {
- int printedMem = -1;
- for (int imem=0; imem<ADJ_MEM_FACTOR_COUNT; imem++) {
- int state = imem+iscreen;
- long time = service.getDuration(serviceType, curState, curStartTime,
- state, now);
- String running = "";
- if (curState == state && pw != null) {
- running = " (running)";
- }
- if (time != 0) {
- if (pw != null) {
- pw.print(prefix);
- printScreenLabel(pw, printedScreen != iscreen
- ? iscreen : STATE_NOTHING);
- printedScreen = iscreen;
- printMemLabel(pw, printedMem != imem ? imem : STATE_NOTHING, (char)0);
- printedMem = imem;
- pw.print(": ");
- TimeUtils.formatDuration(time, pw); pw.println(running);
- }
- totalTime += time;
- }
- }
- }
- if (totalTime != 0 && pw != null) {
- pw.print(prefix);
- pw.print(" TOTAL: ");
- TimeUtils.formatDuration(totalTime, pw);
- pw.println();
- }
- return totalTime;
- }
-
- void dumpServiceStats(PrintWriter pw, String prefix, String prefixInner,
- String headerPrefix, String header, ServiceState service,
- int count, int serviceType, int state, long startTime, long now, long totalTime,
- boolean dumpAll) {
- if (count != 0) {
- if (dumpAll) {
- pw.print(prefix); pw.print(header);
- pw.print(" op count "); pw.print(count); pw.println(":");
- dumpSingleServiceTime(pw, prefixInner, service, serviceType, state, startTime,
- now);
- } else {
- long myTime = dumpSingleServiceTime(null, null, service, serviceType, state,
- startTime, now);
- pw.print(prefix); pw.print(headerPrefix); pw.print(header);
- pw.print(" count "); pw.print(count);
- pw.print(" / time ");
- printPercent(pw, (double)myTime/(double)totalTime);
- pw.println();
- }
- }
- }
-
- public void dumpSummaryLocked(PrintWriter pw, String reqPackage, long now, boolean activeOnly) {
- long totalTime = dumpSingleTime(null, null, mMemFactorDurations, mMemFactor,
- mStartTime, now);
- dumpFilteredSummaryLocked(pw, null, " ", ALL_SCREEN_ADJ, ALL_MEM_ADJ,
- ALL_PROC_STATES, NON_CACHED_PROC_STATES, now, totalTime, reqPackage, activeOnly);
- pw.println();
- dumpTotalsLocked(pw, now);
- }
-
- long printMemoryCategory(PrintWriter pw, String prefix, String label, double memWeight,
- long totalTime, long curTotalMem, int samples) {
- if (memWeight != 0) {
- long mem = (long)(memWeight * 1024 / totalTime);
- pw.print(prefix);
- pw.print(label);
- pw.print(": ");
- DebugUtils.printSizeValue(pw, mem);
- pw.print(" (");
- pw.print(samples);
- pw.print(" samples)");
- pw.println();
- return curTotalMem + mem;
- }
- return curTotalMem;
- }
-
- void dumpTotalsLocked(PrintWriter pw, long now) {
- pw.println("Run time Stats:");
- dumpSingleTime(pw, " ", mMemFactorDurations, mMemFactor, mStartTime, now);
- pw.println();
- pw.println("Memory usage:");
- TotalMemoryUseCollection totalMem = new TotalMemoryUseCollection(ALL_SCREEN_ADJ,
- ALL_MEM_ADJ);
- computeTotalMemoryUse(totalMem, now);
- long totalPss = 0;
- totalPss = printMemoryCategory(pw, " ", "Kernel ", totalMem.sysMemKernelWeight,
- totalMem.totalTime, totalPss, totalMem.sysMemSamples);
- totalPss = printMemoryCategory(pw, " ", "Native ", totalMem.sysMemNativeWeight,
- totalMem.totalTime, totalPss, totalMem.sysMemSamples);
- for (int i=0; i<STATE_COUNT; i++) {
- // Skip restarting service state -- that is not actually a running process.
- if (i != STATE_SERVICE_RESTARTING) {
- totalPss = printMemoryCategory(pw, " ", STATE_NAMES[i],
- totalMem.processStateWeight[i], totalMem.totalTime, totalPss,
- totalMem.processStateSamples[i]);
- }
- }
- totalPss = printMemoryCategory(pw, " ", "Cached ", totalMem.sysMemCachedWeight,
- totalMem.totalTime, totalPss, totalMem.sysMemSamples);
- totalPss = printMemoryCategory(pw, " ", "Free ", totalMem.sysMemFreeWeight,
- totalMem.totalTime, totalPss, totalMem.sysMemSamples);
- totalPss = printMemoryCategory(pw, " ", "Z-Ram ", totalMem.sysMemZRamWeight,
- totalMem.totalTime, totalPss, totalMem.sysMemSamples);
- pw.print(" TOTAL : ");
- DebugUtils.printSizeValue(pw, totalPss);
- pw.println();
- printMemoryCategory(pw, " ", STATE_NAMES[STATE_SERVICE_RESTARTING],
- totalMem.processStateWeight[STATE_SERVICE_RESTARTING], totalMem.totalTime, totalPss,
- totalMem.processStateSamples[STATE_SERVICE_RESTARTING]);
- pw.println();
- pw.print(" Start time: ");
- pw.print(DateFormat.format("yyyy-MM-dd HH:mm:ss", mTimePeriodStartClock));
- pw.println();
- pw.print(" Total elapsed time: ");
- TimeUtils.formatDuration(
- (mRunning ? SystemClock.elapsedRealtime() : mTimePeriodEndRealtime)
- - mTimePeriodStartRealtime, pw);
- boolean partial = true;
- if ((mFlags&FLAG_SHUTDOWN) != 0) {
- pw.print(" (shutdown)");
- partial = false;
- }
- if ((mFlags&FLAG_SYSPROPS) != 0) {
- pw.print(" (sysprops)");
- partial = false;
- }
- if ((mFlags&FLAG_COMPLETE) != 0) {
- pw.print(" (complete)");
- partial = false;
- }
- if (partial) {
- pw.print(" (partial)");
- }
- pw.print(' ');
- pw.print(mRuntime);
- pw.println();
- }
-
- void dumpFilteredSummaryLocked(PrintWriter pw, String header, String prefix,
- int[] screenStates, int[] memStates, int[] procStates,
- int[] sortProcStates, long now, long totalTime, String reqPackage, boolean activeOnly) {
- ArrayList<ProcessState> procs = collectProcessesLocked(screenStates, memStates,
- procStates, sortProcStates, now, reqPackage, activeOnly);
- if (procs.size() > 0) {
- if (header != null) {
- pw.println();
- pw.println(header);
- }
- dumpProcessSummaryLocked(pw, prefix, procs, screenStates, memStates,
- sortProcStates, true, now, totalTime);
- }
- }
-
- public ArrayList<ProcessState> collectProcessesLocked(int[] screenStates, int[] memStates,
- int[] procStates, int sortProcStates[], long now, String reqPackage,
- boolean activeOnly) {
- final ArraySet<ProcessState> foundProcs = new ArraySet<ProcessState>();
- final ArrayMap<String, SparseArray<SparseArray<PackageState>>> pkgMap = mPackages.getMap();
- for (int ip=0; ip<pkgMap.size(); ip++) {
- final String pkgName = pkgMap.keyAt(ip);
- final SparseArray<SparseArray<PackageState>> procs = pkgMap.valueAt(ip);
- for (int iu=0; iu<procs.size(); iu++) {
- final SparseArray<PackageState> vpkgs = procs.valueAt(iu);
- final int NVERS = vpkgs.size();
- for (int iv=0; iv<NVERS; iv++) {
- final PackageState state = vpkgs.valueAt(iv);
- final int NPROCS = state.mProcesses.size();
- final boolean pkgMatch = reqPackage == null || reqPackage.equals(pkgName);
- for (int iproc=0; iproc<NPROCS; iproc++) {
- final ProcessState proc = state.mProcesses.valueAt(iproc);
- if (!pkgMatch && !reqPackage.equals(proc.mName)) {
- continue;
- }
- if (activeOnly && !proc.isInUse()) {
- continue;
- }
- foundProcs.add(proc.mCommonProcess);
- }
- }
- }
- }
- ArrayList<ProcessState> outProcs = new ArrayList<ProcessState>(foundProcs.size());
- for (int i=0; i<foundProcs.size(); i++) {
- ProcessState proc = foundProcs.valueAt(i);
- if (computeProcessTimeLocked(proc, screenStates, memStates, procStates, now) > 0) {
- outProcs.add(proc);
- if (procStates != sortProcStates) {
- computeProcessTimeLocked(proc, screenStates, memStates, sortProcStates, now);
- }
- }
- }
- Collections.sort(outProcs, new Comparator<ProcessState>() {
- @Override
- public int compare(ProcessState lhs, ProcessState rhs) {
- if (lhs.mTmpTotalTime < rhs.mTmpTotalTime) {
- return -1;
- } else if (lhs.mTmpTotalTime > rhs.mTmpTotalTime) {
- return 1;
- }
- return 0;
- }
- });
- return outProcs;
- }
-
- String collapseString(String pkgName, String itemName) {
- if (itemName.startsWith(pkgName)) {
- final int ITEMLEN = itemName.length();
- final int PKGLEN = pkgName.length();
- if (ITEMLEN == PKGLEN) {
- return "";
- } else if (ITEMLEN >= PKGLEN) {
- if (itemName.charAt(PKGLEN) == '.') {
- return itemName.substring(PKGLEN);
- }
- }
- }
- return itemName;
- }
-
- public void dumpCheckinLocked(PrintWriter pw, String reqPackage) {
- final long now = SystemClock.uptimeMillis();
- final ArrayMap<String, SparseArray<SparseArray<PackageState>>> pkgMap = mPackages.getMap();
- pw.println("vers,5");
- pw.print("period,"); pw.print(mTimePeriodStartClockStr);
- pw.print(","); pw.print(mTimePeriodStartRealtime); pw.print(",");
- pw.print(mRunning ? SystemClock.elapsedRealtime() : mTimePeriodEndRealtime);
- boolean partial = true;
- if ((mFlags&FLAG_SHUTDOWN) != 0) {
- pw.print(",shutdown");
- partial = false;
- }
- if ((mFlags&FLAG_SYSPROPS) != 0) {
- pw.print(",sysprops");
- partial = false;
- }
- if ((mFlags&FLAG_COMPLETE) != 0) {
- pw.print(",complete");
- partial = false;
- }
- if (partial) {
- pw.print(",partial");
- }
- pw.println();
- pw.print("config,"); pw.println(mRuntime);
- for (int ip=0; ip<pkgMap.size(); ip++) {
- final String pkgName = pkgMap.keyAt(ip);
- if (reqPackage != null && !reqPackage.equals(pkgName)) {
- continue;
- }
- final SparseArray<SparseArray<PackageState>> uids = pkgMap.valueAt(ip);
- for (int iu=0; iu<uids.size(); iu++) {
- final int uid = uids.keyAt(iu);
- final SparseArray<PackageState> vpkgs = uids.valueAt(iu);
- for (int iv=0; iv<vpkgs.size(); iv++) {
- final int vers = vpkgs.keyAt(iv);
- final PackageState pkgState = vpkgs.valueAt(iv);
- final int NPROCS = pkgState.mProcesses.size();
- final int NSRVS = pkgState.mServices.size();
- for (int iproc=0; iproc<NPROCS; iproc++) {
- ProcessState proc = pkgState.mProcesses.valueAt(iproc);
- pw.print("pkgproc,");
- pw.print(pkgName);
- pw.print(",");
- pw.print(uid);
- pw.print(",");
- pw.print(vers);
- pw.print(",");
- pw.print(collapseString(pkgName, pkgState.mProcesses.keyAt(iproc)));
- dumpAllProcessStateCheckin(pw, proc, now);
- pw.println();
- if (proc.mPssTableSize > 0) {
- pw.print("pkgpss,");
- pw.print(pkgName);
- pw.print(",");
- pw.print(uid);
- pw.print(",");
- pw.print(vers);
- pw.print(",");
- pw.print(collapseString(pkgName, pkgState.mProcesses.keyAt(iproc)));
- dumpAllProcessPssCheckin(pw, proc);
- pw.println();
- }
- if (proc.mNumExcessiveWake > 0 || proc.mNumExcessiveCpu > 0
- || proc.mNumCachedKill > 0) {
- pw.print("pkgkills,");
- pw.print(pkgName);
- pw.print(",");
- pw.print(uid);
- pw.print(",");
- pw.print(vers);
- pw.print(",");
- pw.print(collapseString(pkgName, pkgState.mProcesses.keyAt(iproc)));
- pw.print(",");
- pw.print(proc.mNumExcessiveWake);
- pw.print(",");
- pw.print(proc.mNumExcessiveCpu);
- pw.print(",");
- pw.print(proc.mNumCachedKill);
- pw.print(",");
- pw.print(proc.mMinCachedKillPss);
- pw.print(":");
- pw.print(proc.mAvgCachedKillPss);
- pw.print(":");
- pw.print(proc.mMaxCachedKillPss);
- pw.println();
- }
- }
- for (int isvc=0; isvc<NSRVS; isvc++) {
- String serviceName = collapseString(pkgName,
- pkgState.mServices.keyAt(isvc));
- ServiceState svc = pkgState.mServices.valueAt(isvc);
- dumpServiceTimeCheckin(pw, "pkgsvc-run", pkgName, uid, vers, serviceName,
- svc, ServiceState.SERVICE_RUN, svc.mRunCount,
- svc.mRunState, svc.mRunStartTime, now);
- dumpServiceTimeCheckin(pw, "pkgsvc-start", pkgName, uid, vers, serviceName,
- svc, ServiceState.SERVICE_STARTED, svc.mStartedCount,
- svc.mStartedState, svc.mStartedStartTime, now);
- dumpServiceTimeCheckin(pw, "pkgsvc-bound", pkgName, uid, vers, serviceName,
- svc, ServiceState.SERVICE_BOUND, svc.mBoundCount,
- svc.mBoundState, svc.mBoundStartTime, now);
- dumpServiceTimeCheckin(pw, "pkgsvc-exec", pkgName, uid, vers, serviceName,
- svc, ServiceState.SERVICE_EXEC, svc.mExecCount,
- svc.mExecState, svc.mExecStartTime, now);
- }
- }
- }
- }
-
- ArrayMap<String, SparseArray<ProcessState>> procMap = mProcesses.getMap();
- for (int ip=0; ip<procMap.size(); ip++) {
- String procName = procMap.keyAt(ip);
- SparseArray<ProcessState> uids = procMap.valueAt(ip);
- for (int iu=0; iu<uids.size(); iu++) {
- int uid = uids.keyAt(iu);
- ProcessState procState = uids.valueAt(iu);
- if (procState.mDurationsTableSize > 0) {
- pw.print("proc,");
- pw.print(procName);
- pw.print(",");
- pw.print(uid);
- dumpAllProcessStateCheckin(pw, procState, now);
- pw.println();
- }
- if (procState.mPssTableSize > 0) {
- pw.print("pss,");
- pw.print(procName);
- pw.print(",");
- pw.print(uid);
- dumpAllProcessPssCheckin(pw, procState);
- pw.println();
- }
- if (procState.mNumExcessiveWake > 0 || procState.mNumExcessiveCpu > 0
- || procState.mNumCachedKill > 0) {
- pw.print("kills,");
- pw.print(procName);
- pw.print(",");
- pw.print(uid);
- pw.print(",");
- pw.print(procState.mNumExcessiveWake);
- pw.print(",");
- pw.print(procState.mNumExcessiveCpu);
- pw.print(",");
- pw.print(procState.mNumCachedKill);
- pw.print(",");
- pw.print(procState.mMinCachedKillPss);
- pw.print(":");
- pw.print(procState.mAvgCachedKillPss);
- pw.print(":");
- pw.print(procState.mMaxCachedKillPss);
- pw.println();
- }
- }
- }
- pw.print("total");
- dumpAdjTimesCheckin(pw, ",", mMemFactorDurations, mMemFactor,
- mStartTime, now);
- pw.println();
- if (mSysMemUsageTable != null) {
- pw.print("sysmemusage");
- for (int i=0; i<mSysMemUsageTableSize; i++) {
- int off = mSysMemUsageTable[i];
- int type = (off>>OFFSET_TYPE_SHIFT)&OFFSET_TYPE_MASK;
- pw.print(",");
- printProcStateTag(pw, type);
- for (int j=SYS_MEM_USAGE_SAMPLE_COUNT; j<SYS_MEM_USAGE_COUNT; j++) {
- if (j > SYS_MEM_USAGE_CACHED_MINIMUM) {
- pw.print(":");
- }
- pw.print(getLong(off, j));
- }
- }
- }
- pw.println();
- TotalMemoryUseCollection totalMem = new TotalMemoryUseCollection(ALL_SCREEN_ADJ,
- ALL_MEM_ADJ);
- computeTotalMemoryUse(totalMem, now);
- pw.print("weights,");
- pw.print(totalMem.totalTime);
- pw.print(",");
- pw.print(totalMem.sysMemCachedWeight);
- pw.print(":");
- pw.print(totalMem.sysMemSamples);
- pw.print(",");
- pw.print(totalMem.sysMemFreeWeight);
- pw.print(":");
- pw.print(totalMem.sysMemSamples);
- pw.print(",");
- pw.print(totalMem.sysMemZRamWeight);
- pw.print(":");
- pw.print(totalMem.sysMemSamples);
- pw.print(",");
- pw.print(totalMem.sysMemKernelWeight);
- pw.print(":");
- pw.print(totalMem.sysMemSamples);
- pw.print(",");
- pw.print(totalMem.sysMemNativeWeight);
- pw.print(":");
- pw.print(totalMem.sysMemSamples);
- for (int i=0; i<STATE_COUNT; i++) {
- pw.print(",");
- pw.print(totalMem.processStateWeight[i]);
- pw.print(":");
- pw.print(totalMem.processStateSamples[i]);
- }
- pw.println();
- }
-
- public static class DurationsTable {
- public final ProcessStats mStats;
- public final String mName;
- public int[] mDurationsTable;
- public int mDurationsTableSize;
-
- public DurationsTable(ProcessStats stats, String name) {
- mStats = stats;
- mName = name;
- }
-
- void copyDurationsTo(DurationsTable other) {
- if (mDurationsTable != null) {
- mStats.mAddLongTable = new int[mDurationsTable.length];
- mStats.mAddLongTableSize = 0;
- for (int i=0; i<mDurationsTableSize; i++) {
- int origEnt = mDurationsTable[i];
- int type = (origEnt>>OFFSET_TYPE_SHIFT)&OFFSET_TYPE_MASK;
- int newOff = mStats.addLongData(i, type, 1);
- mStats.mAddLongTable[i] = newOff | type;
- mStats.setLong(newOff, 0, mStats.getLong(origEnt, 0));
- }
- other.mDurationsTable = mStats.mAddLongTable;
- other.mDurationsTableSize = mStats.mAddLongTableSize;
- } else {
- other.mDurationsTable = null;
- other.mDurationsTableSize = 0;
- }
- }
-
- void addDurations(DurationsTable other) {
- for (int i=0; i<other.mDurationsTableSize; i++) {
- int ent = other.mDurationsTable[i];
- int state = (ent>>OFFSET_TYPE_SHIFT)&OFFSET_TYPE_MASK;
- if (DEBUG) Slog.d(TAG, "Adding state " + state + " duration "
- + other.mStats.getLong(ent, 0));
- addDuration(state, other.mStats.getLong(ent, 0));
- }
- }
-
- void resetDurationsSafely() {
- mDurationsTable = null;
- mDurationsTableSize = 0;
- }
-
- void writeDurationsToParcel(Parcel out) {
- out.writeInt(mDurationsTableSize);
- for (int i=0; i<mDurationsTableSize; i++) {
- if (DEBUG_PARCEL) Slog.i(TAG, "Writing in " + mName + " dur #" + i + ": "
- + printLongOffset(mDurationsTable[i]));
- out.writeInt(mDurationsTable[i]);
- }
- }
-
- boolean readDurationsFromParcel(Parcel in) {
- mDurationsTable = mStats.readTableFromParcel(in, mName, "durations");
- if (mDurationsTable == BAD_TABLE) {
- return false;
- }
- mDurationsTableSize = mDurationsTable != null ? mDurationsTable.length : 0;
- return true;
- }
-
- void addDuration(int state, long dur) {
- int idx = binarySearch(mDurationsTable, mDurationsTableSize, state);
- int off;
- if (idx >= 0) {
- off = mDurationsTable[idx];
- } else {
- mStats.mAddLongTable = mDurationsTable;
- mStats.mAddLongTableSize = mDurationsTableSize;
- off = mStats.addLongData(~idx, state, 1);
- mDurationsTable = mStats.mAddLongTable;
- mDurationsTableSize = mStats.mAddLongTableSize;
- }
- long[] longs = mStats.mLongs.get((off>>OFFSET_ARRAY_SHIFT)&OFFSET_ARRAY_MASK);
- if (DEBUG) Slog.d(TAG, "Duration of " + mName + " state " + state + " inc by " + dur
- + " from " + longs[(off>>OFFSET_INDEX_SHIFT)&OFFSET_INDEX_MASK]);
- longs[(off>>OFFSET_INDEX_SHIFT)&OFFSET_INDEX_MASK] += dur;
- }
-
- long getDuration(int state, long now) {
- int idx = binarySearch(mDurationsTable, mDurationsTableSize, state);
- return idx >= 0 ? mStats.getLong(mDurationsTable[idx], 0) : 0;
- }
- }
-
- final public static class ProcessStateHolder {
- public final int appVersion;
- public ProcessStats.ProcessState state;
-
- public ProcessStateHolder(int _appVersion) {
- appVersion = _appVersion;
- }
- }
-
- public static final class ProcessState extends DurationsTable {
- public ProcessState mCommonProcess;
- public final String mPackage;
- public final int mUid;
- public final int mVersion;
-
- //final long[] mDurations = new long[STATE_COUNT*ADJ_COUNT];
- int mCurState = STATE_NOTHING;
- long mStartTime;
-
- int mLastPssState = STATE_NOTHING;
- long mLastPssTime;
- int[] mPssTable;
- int mPssTableSize;
-
- boolean mActive;
- int mNumActiveServices;
- int mNumStartedServices;
-
- int mNumExcessiveWake;
- int mNumExcessiveCpu;
-
- int mNumCachedKill;
- long mMinCachedKillPss;
- long mAvgCachedKillPss;
- long mMaxCachedKillPss;
-
- boolean mMultiPackage;
- boolean mDead;
-
- public long mTmpTotalTime;
- int mTmpNumInUse;
- ProcessState mTmpFoundSubProc;
-
- /**
- * Create a new top-level process state, for the initial case where there is only
- * a single package running in a process. The initial state is not running.
- */
- public ProcessState(ProcessStats processStats, String pkg, int uid, int vers, String name) {
- super(processStats, name);
- mCommonProcess = this;
- mPackage = pkg;
- mUid = uid;
- mVersion = vers;
- }
-
- /**
- * Create a new per-package process state for an existing top-level process
- * state. The current running state of the top-level process is also copied,
- * marked as started running at 'now'.
- */
- public ProcessState(ProcessState commonProcess, String pkg, int uid, int vers, String name,
- long now) {
- super(commonProcess.mStats, name);
- mCommonProcess = commonProcess;
- mPackage = pkg;
- mUid = uid;
- mVersion = vers;
- mCurState = commonProcess.mCurState;
- mStartTime = now;
- }
-
- ProcessState clone(String pkg, long now) {
- ProcessState pnew = new ProcessState(this, pkg, mUid, mVersion, mName, now);
- copyDurationsTo(pnew);
- if (mPssTable != null) {
- mStats.mAddLongTable = new int[mPssTable.length];
- mStats.mAddLongTableSize = 0;
- for (int i=0; i<mPssTableSize; i++) {
- int origEnt = mPssTable[i];
- int type = (origEnt>>OFFSET_TYPE_SHIFT)&OFFSET_TYPE_MASK;
- int newOff = mStats.addLongData(i, type, PSS_COUNT);
- mStats.mAddLongTable[i] = newOff | type;
- for (int j=0; j<PSS_COUNT; j++) {
- mStats.setLong(newOff, j, mStats.getLong(origEnt, j));
- }
- }
- pnew.mPssTable = mStats.mAddLongTable;
- pnew.mPssTableSize = mStats.mAddLongTableSize;
- }
- pnew.mNumExcessiveWake = mNumExcessiveWake;
- pnew.mNumExcessiveCpu = mNumExcessiveCpu;
- pnew.mNumCachedKill = mNumCachedKill;
- pnew.mMinCachedKillPss = mMinCachedKillPss;
- pnew.mAvgCachedKillPss = mAvgCachedKillPss;
- pnew.mMaxCachedKillPss = mMaxCachedKillPss;
- pnew.mActive = mActive;
- pnew.mNumActiveServices = mNumActiveServices;
- pnew.mNumStartedServices = mNumStartedServices;
- return pnew;
- }
-
- void add(ProcessState other) {
- addDurations(other);
- for (int i=0; i<other.mPssTableSize; i++) {
- int ent = other.mPssTable[i];
- int state = (ent>>OFFSET_TYPE_SHIFT)&OFFSET_TYPE_MASK;
- addPss(state, (int) other.mStats.getLong(ent, PSS_SAMPLE_COUNT),
- other.mStats.getLong(ent, PSS_MINIMUM),
- other.mStats.getLong(ent, PSS_AVERAGE),
- other.mStats.getLong(ent, PSS_MAXIMUM),
- other.mStats.getLong(ent, PSS_USS_MINIMUM),
- other.mStats.getLong(ent, PSS_USS_AVERAGE),
- other.mStats.getLong(ent, PSS_USS_MAXIMUM));
- }
- mNumExcessiveWake += other.mNumExcessiveWake;
- mNumExcessiveCpu += other.mNumExcessiveCpu;
- if (other.mNumCachedKill > 0) {
- addCachedKill(other.mNumCachedKill, other.mMinCachedKillPss,
- other.mAvgCachedKillPss, other.mMaxCachedKillPss);
- }
- }
-
- void resetSafely(long now) {
- resetDurationsSafely();
- mStartTime = now;
- mLastPssState = STATE_NOTHING;
- mLastPssTime = 0;
- mPssTable = null;
- mPssTableSize = 0;
- mNumExcessiveWake = 0;
- mNumExcessiveCpu = 0;
- mNumCachedKill = 0;
- mMinCachedKillPss = mAvgCachedKillPss = mMaxCachedKillPss = 0;
- }
-
- void makeDead() {
- mDead = true;
- }
-
- private void ensureNotDead() {
- if (!mDead) {
- return;
- }
- Slog.wtfStack(TAG, "ProcessState dead: name=" + mName
- + " pkg=" + mPackage + " uid=" + mUid + " common.name=" + mCommonProcess.mName);
- }
-
- void writeToParcel(Parcel out, long now) {
- out.writeInt(mMultiPackage ? 1 : 0);
- writeDurationsToParcel(out);
- out.writeInt(mPssTableSize);
- for (int i=0; i<mPssTableSize; i++) {
- if (DEBUG_PARCEL) Slog.i(TAG, "Writing in " + mName + " pss #" + i + ": "
- + printLongOffset(mPssTable[i]));
- out.writeInt(mPssTable[i]);
- }
- out.writeInt(mNumExcessiveWake);
- out.writeInt(mNumExcessiveCpu);
- out.writeInt(mNumCachedKill);
- if (mNumCachedKill > 0) {
- out.writeLong(mMinCachedKillPss);
- out.writeLong(mAvgCachedKillPss);
- out.writeLong(mMaxCachedKillPss);
- }
- }
-
- boolean readFromParcel(Parcel in, boolean fully) {
- boolean multiPackage = in.readInt() != 0;
- if (fully) {
- mMultiPackage = multiPackage;
- }
- if (DEBUG_PARCEL) Slog.d(TAG, "Reading durations table...");
- if (!readDurationsFromParcel(in)) {
- return false;
- }
- if (DEBUG_PARCEL) Slog.d(TAG, "Reading pss table...");
- mPssTable = mStats.readTableFromParcel(in, mName, "pss");
- if (mPssTable == BAD_TABLE) {
- return false;
- }
- mPssTableSize = mPssTable != null ? mPssTable.length : 0;
- mNumExcessiveWake = in.readInt();
- mNumExcessiveCpu = in.readInt();
- mNumCachedKill = in.readInt();
- if (mNumCachedKill > 0) {
- mMinCachedKillPss = in.readLong();
- mAvgCachedKillPss = in.readLong();
- mMaxCachedKillPss = in.readLong();
- } else {
- mMinCachedKillPss = mAvgCachedKillPss = mMaxCachedKillPss = 0;
- }
- return true;
- }
-
- public void makeActive() {
- ensureNotDead();
- mActive = true;
- }
-
- public void makeInactive() {
- mActive = false;
- }
-
- public boolean isInUse() {
- return mActive || mNumActiveServices > 0 || mNumStartedServices > 0
- || mCurState != STATE_NOTHING;
- }
-
- /**
- * Update the current state of the given list of processes.
- *
- * @param state Current ActivityManager.PROCESS_STATE_*
- * @param memFactor Current mem factor constant.
- * @param now Current time.
- * @param pkgList Processes to update.
- */
- public void setState(int state, int memFactor, long now,
- ArrayMap<String, ProcessStateHolder> pkgList) {
- if (state < 0) {
- state = mNumStartedServices > 0
- ? (STATE_SERVICE_RESTARTING+(memFactor*STATE_COUNT)) : STATE_NOTHING;
- } else {
- state = PROCESS_STATE_TO_STATE[state] + (memFactor*STATE_COUNT);
- }
-
- // First update the common process.
- mCommonProcess.setState(state, now);
-
- // If the common process is not multi-package, there is nothing else to do.
- if (!mCommonProcess.mMultiPackage) {
- return;
- }
-
- if (pkgList != null) {
- for (int ip=pkgList.size()-1; ip>=0; ip--) {
- pullFixedProc(pkgList, ip).setState(state, now);
- }
- }
- }
-
- void setState(int state, long now) {
- ensureNotDead();
- if (mCurState != state) {
- //Slog.i(TAG, "Setting state in " + mName + "/" + mPackage + ": " + state);
- commitStateTime(now);
- mCurState = state;
- }
- }
-
- void commitStateTime(long now) {
- if (mCurState != STATE_NOTHING) {
- long dur = now - mStartTime;
- if (dur > 0) {
- addDuration(mCurState, dur);
- }
- }
- mStartTime = now;
- }
-
- void incActiveServices(String serviceName) {
- if (DEBUG && "".equals(mName)) {
- RuntimeException here = new RuntimeException("here");
- here.fillInStackTrace();
- Slog.d(TAG, "incActiveServices: " + this + " service=" + serviceName
- + " to " + (mNumActiveServices+1), here);
- }
- if (mCommonProcess != this) {
- mCommonProcess.incActiveServices(serviceName);
- }
- mNumActiveServices++;
- }
-
- void decActiveServices(String serviceName) {
- if (DEBUG && "".equals(mName)) {
- RuntimeException here = new RuntimeException("here");
- here.fillInStackTrace();
- Slog.d(TAG, "decActiveServices: " + this + " service=" + serviceName
- + " to " + (mNumActiveServices-1), here);
- }
- if (mCommonProcess != this) {
- mCommonProcess.decActiveServices(serviceName);
- }
- mNumActiveServices--;
- if (mNumActiveServices < 0) {
- Slog.wtfStack(TAG, "Proc active services underrun: pkg=" + mPackage
- + " uid=" + mUid + " proc=" + mName + " service=" + serviceName);
- mNumActiveServices = 0;
- }
- }
-
- void incStartedServices(int memFactor, long now, String serviceName) {
- if (false) {
- RuntimeException here = new RuntimeException("here");
- here.fillInStackTrace();
- Slog.d(TAG, "incStartedServices: " + this + " service=" + serviceName
- + " to " + (mNumStartedServices+1), here);
- }
- if (mCommonProcess != this) {
- mCommonProcess.incStartedServices(memFactor, now, serviceName);
- }
- mNumStartedServices++;
- if (mNumStartedServices == 1 && mCurState == STATE_NOTHING) {
- setState(STATE_SERVICE_RESTARTING + (memFactor*STATE_COUNT), now);
- }
- }
-
- void decStartedServices(int memFactor, long now, String serviceName) {
- if (false) {
- RuntimeException here = new RuntimeException("here");
- here.fillInStackTrace();
- Slog.d(TAG, "decActiveServices: " + this + " service=" + serviceName
- + " to " + (mNumStartedServices-1), here);
- }
- if (mCommonProcess != this) {
- mCommonProcess.decStartedServices(memFactor, now, serviceName);
- }
- mNumStartedServices--;
- if (mNumStartedServices == 0 && (mCurState%STATE_COUNT) == STATE_SERVICE_RESTARTING) {
- setState(STATE_NOTHING, now);
- } else if (mNumStartedServices < 0) {
- Slog.wtfStack(TAG, "Proc started services underrun: pkg="
- + mPackage + " uid=" + mUid + " name=" + mName);
- mNumStartedServices = 0;
- }
- }
-
- public void addPss(long pss, long uss, boolean always,
- ArrayMap<String, ProcessStateHolder> pkgList) {
- ensureNotDead();
- if (!always) {
- if (mLastPssState == mCurState && SystemClock.uptimeMillis()
- < (mLastPssTime+(30*1000))) {
- return;
- }
- }
- mLastPssState = mCurState;
- mLastPssTime = SystemClock.uptimeMillis();
- if (mCurState != STATE_NOTHING) {
- // First update the common process.
- mCommonProcess.addPss(mCurState, 1, pss, pss, pss, uss, uss, uss);
-
- // If the common process is not multi-package, there is nothing else to do.
- if (!mCommonProcess.mMultiPackage) {
- return;
- }
-
- if (pkgList != null) {
- for (int ip=pkgList.size()-1; ip>=0; ip--) {
- pullFixedProc(pkgList, ip).addPss(mCurState, 1,
- pss, pss, pss, uss, uss, uss);
- }
- }
- }
- }
-
- void addPss(int state, int inCount, long minPss, long avgPss, long maxPss, long minUss,
- long avgUss, long maxUss) {
- int idx = binarySearch(mPssTable, mPssTableSize, state);
- int off;
- if (idx >= 0) {
- off = mPssTable[idx];
- } else {
- mStats.mAddLongTable = mPssTable;
- mStats.mAddLongTableSize = mPssTableSize;
- off = mStats.addLongData(~idx, state, PSS_COUNT);
- mPssTable = mStats.mAddLongTable;
- mPssTableSize = mStats.mAddLongTableSize;
- }
- long[] longs = mStats.mLongs.get((off>>OFFSET_ARRAY_SHIFT)&OFFSET_ARRAY_MASK);
- idx = (off>>OFFSET_INDEX_SHIFT)&OFFSET_INDEX_MASK;
- long count = longs[idx+PSS_SAMPLE_COUNT];
- if (count == 0) {
- longs[idx+PSS_SAMPLE_COUNT] = inCount;
- longs[idx+PSS_MINIMUM] = minPss;
- longs[idx+PSS_AVERAGE] = avgPss;
- longs[idx+PSS_MAXIMUM] = maxPss;
- longs[idx+PSS_USS_MINIMUM] = minUss;
- longs[idx+PSS_USS_AVERAGE] = avgUss;
- longs[idx+PSS_USS_MAXIMUM] = maxUss;
- } else {
- longs[idx+PSS_SAMPLE_COUNT] = count+inCount;
- if (longs[idx+PSS_MINIMUM] > minPss) {
- longs[idx+PSS_MINIMUM] = minPss;
- }
- longs[idx+PSS_AVERAGE] = (long)(
- ((longs[idx+PSS_AVERAGE]*(double)count)+(avgPss*(double)inCount))
- / (count+inCount) );
- if (longs[idx+PSS_MAXIMUM] < maxPss) {
- longs[idx+PSS_MAXIMUM] = maxPss;
- }
- if (longs[idx+PSS_USS_MINIMUM] > minUss) {
- longs[idx+PSS_USS_MINIMUM] = minUss;
- }
- longs[idx+PSS_USS_AVERAGE] = (long)(
- ((longs[idx+PSS_USS_AVERAGE]*(double)count)+(avgUss*(double)inCount))
- / (count+inCount) );
- if (longs[idx+PSS_USS_MAXIMUM] < maxUss) {
- longs[idx+PSS_USS_MAXIMUM] = maxUss;
- }
- }
- }
-
- public void reportExcessiveWake(ArrayMap<String, ProcessStateHolder> pkgList) {
- ensureNotDead();
- mCommonProcess.mNumExcessiveWake++;
- if (!mCommonProcess.mMultiPackage) {
- return;
- }
-
- for (int ip=pkgList.size()-1; ip>=0; ip--) {
- pullFixedProc(pkgList, ip).mNumExcessiveWake++;
- }
- }
-
- public void reportExcessiveCpu(ArrayMap<String, ProcessStateHolder> pkgList) {
- ensureNotDead();
- mCommonProcess.mNumExcessiveCpu++;
- if (!mCommonProcess.mMultiPackage) {
- return;
- }
-
- for (int ip=pkgList.size()-1; ip>=0; ip--) {
- pullFixedProc(pkgList, ip).mNumExcessiveCpu++;
- }
- }
-
- private void addCachedKill(int num, long minPss, long avgPss, long maxPss) {
- if (mNumCachedKill <= 0) {
- mNumCachedKill = num;
- mMinCachedKillPss = minPss;
- mAvgCachedKillPss = avgPss;
- mMaxCachedKillPss = maxPss;
- } else {
- if (minPss < mMinCachedKillPss) {
- mMinCachedKillPss = minPss;
- }
- if (maxPss > mMaxCachedKillPss) {
- mMaxCachedKillPss = maxPss;
- }
- mAvgCachedKillPss = (long)( ((mAvgCachedKillPss*(double)mNumCachedKill) + avgPss)
- / (mNumCachedKill+num) );
- mNumCachedKill += num;
- }
- }
-
- public void reportCachedKill(ArrayMap<String, ProcessStateHolder> pkgList, long pss) {
- ensureNotDead();
- mCommonProcess.addCachedKill(1, pss, pss, pss);
- if (!mCommonProcess.mMultiPackage) {
- return;
- }
-
- for (int ip=pkgList.size()-1; ip>=0; ip--) {
- pullFixedProc(pkgList, ip).addCachedKill(1, pss, pss, pss);
- }
- }
-
- ProcessState pullFixedProc(String pkgName) {
- if (mMultiPackage) {
- // The array map is still pointing to a common process state
- // that is now shared across packages. Update it to point to
- // the new per-package state.
- SparseArray<PackageState> vpkg = mStats.mPackages.get(pkgName, mUid);
- if (vpkg == null) {
- throw new IllegalStateException("Didn't find package " + pkgName
- + " / " + mUid);
- }
- PackageState pkg = vpkg.get(mVersion);
- if (pkg == null) {
- throw new IllegalStateException("Didn't find package " + pkgName
- + " / " + mUid + " vers " + mVersion);
- }
- ProcessState proc = pkg.mProcesses.get(mName);
- if (proc == null) {
- throw new IllegalStateException("Didn't create per-package process "
- + mName + " in pkg " + pkgName + " / " + mUid + " vers " + mVersion);
- }
- return proc;
- }
- return this;
- }
-
- private ProcessState pullFixedProc(ArrayMap<String, ProcessStateHolder> pkgList,
- int index) {
- ProcessStateHolder holder = pkgList.valueAt(index);
- ProcessState proc = holder.state;
- if (mDead && proc.mCommonProcess != proc) {
- // Somehow we are contining to use a process state that is dead, because
- // it was not being told it was active during the last commit. We can recover
- // from this by generating a fresh new state, but this is bad because we
- // are losing whatever data we had in the old process state.
- Log.wtf(TAG, "Pulling dead proc: name=" + mName + " pkg=" + mPackage
- + " uid=" + mUid + " common.name=" + mCommonProcess.mName);
- proc = mStats.getProcessStateLocked(proc.mPackage, proc.mUid, proc.mVersion,
- proc.mName);
- }
- if (proc.mMultiPackage) {
- // The array map is still pointing to a common process state
- // that is now shared across packages. Update it to point to
- // the new per-package state.
- SparseArray<PackageState> vpkg = mStats.mPackages.get(pkgList.keyAt(index),
- proc.mUid);
- if (vpkg == null) {
- throw new IllegalStateException("No existing package "
- + pkgList.keyAt(index) + "/" + proc.mUid
- + " for multi-proc " + proc.mName);
- }
- PackageState pkg = vpkg.get(proc.mVersion);
- if (pkg == null) {
- throw new IllegalStateException("No existing package "
- + pkgList.keyAt(index) + "/" + proc.mUid
- + " for multi-proc " + proc.mName + " version " + proc.mVersion);
- }
- String savedName = proc.mName;
- proc = pkg.mProcesses.get(proc.mName);
- if (proc == null) {
- throw new IllegalStateException("Didn't create per-package process "
- + savedName + " in pkg " + pkg.mPackageName + "/" + pkg.mUid);
- }
- holder.state = proc;
- }
- return proc;
- }
-
- long getDuration(int state, long now) {
- long time = super.getDuration(state, now);
- if (mCurState == state) {
- time += now - mStartTime;
- }
- return time;
- }
-
- long getPssSampleCount(int state) {
- int idx = binarySearch(mPssTable, mPssTableSize, state);
- return idx >= 0 ? mStats.getLong(mPssTable[idx], PSS_SAMPLE_COUNT) : 0;
- }
-
- long getPssMinimum(int state) {
- int idx = binarySearch(mPssTable, mPssTableSize, state);
- return idx >= 0 ? mStats.getLong(mPssTable[idx], PSS_MINIMUM) : 0;
- }
-
- long getPssAverage(int state) {
- int idx = binarySearch(mPssTable, mPssTableSize, state);
- return idx >= 0 ? mStats.getLong(mPssTable[idx], PSS_AVERAGE) : 0;
- }
-
- long getPssMaximum(int state) {
- int idx = binarySearch(mPssTable, mPssTableSize, state);
- return idx >= 0 ? mStats.getLong(mPssTable[idx], PSS_MAXIMUM) : 0;
- }
-
- long getPssUssMinimum(int state) {
- int idx = binarySearch(mPssTable, mPssTableSize, state);
- return idx >= 0 ? mStats.getLong(mPssTable[idx], PSS_USS_MINIMUM) : 0;
- }
-
- long getPssUssAverage(int state) {
- int idx = binarySearch(mPssTable, mPssTableSize, state);
- return idx >= 0 ? mStats.getLong(mPssTable[idx], PSS_USS_AVERAGE) : 0;
- }
-
- long getPssUssMaximum(int state) {
- int idx = binarySearch(mPssTable, mPssTableSize, state);
- return idx >= 0 ? mStats.getLong(mPssTable[idx], PSS_USS_MAXIMUM) : 0;
- }
-
- public String toString() {
- StringBuilder sb = new StringBuilder(128);
- sb.append("ProcessState{").append(Integer.toHexString(System.identityHashCode(this)))
- .append(" ").append(mName).append("/").append(mUid)
- .append(" pkg=").append(mPackage);
- if (mMultiPackage) sb.append(" (multi)");
- if (mCommonProcess != this) sb.append(" (sub)");
- sb.append("}");
- return sb.toString();
- }
- }
-
- public static final class ServiceState extends DurationsTable {
- public final String mPackage;
- public final String mProcessName;
- ProcessState mProc;
-
- Object mOwner;
-
- public static final int SERVICE_RUN = 0;
- public static final int SERVICE_STARTED = 1;
- public static final int SERVICE_BOUND = 2;
- public static final int SERVICE_EXEC = 3;
- static final int SERVICE_COUNT = 4;
-
- int mRunCount;
- public int mRunState = STATE_NOTHING;
- long mRunStartTime;
-
- boolean mStarted;
- boolean mRestarting;
- int mStartedCount;
- public int mStartedState = STATE_NOTHING;
- long mStartedStartTime;
-
- int mBoundCount;
- public int mBoundState = STATE_NOTHING;
- long mBoundStartTime;
-
- int mExecCount;
- public int mExecState = STATE_NOTHING;
- long mExecStartTime;
-
- public ServiceState(ProcessStats processStats, String pkg, String name,
- String processName, ProcessState proc) {
- super(processStats, name);
- mPackage = pkg;
- mProcessName = processName;
- mProc = proc;
- }
-
- public void applyNewOwner(Object newOwner) {
- if (mOwner != newOwner) {
- if (mOwner == null) {
- mOwner = newOwner;
- mProc.incActiveServices(mName);
- } else {
- // There was already an old owner, reset this object for its
- // new owner.
- mOwner = newOwner;
- if (mStarted || mBoundState != STATE_NOTHING || mExecState != STATE_NOTHING) {
- long now = SystemClock.uptimeMillis();
- if (mStarted) {
- if (DEBUG) Slog.d(TAG, "Service has new owner " + newOwner
- + " from " + mOwner + " while started: pkg="
- + mPackage + " service=" + mName + " proc=" + mProc);
- setStarted(false, 0, now);
- }
- if (mBoundState != STATE_NOTHING) {
- if (DEBUG) Slog.d(TAG, "Service has new owner " + newOwner
- + " from " + mOwner + " while bound: pkg="
- + mPackage + " service=" + mName + " proc=" + mProc);
- setBound(false, 0, now);
- }
- if (mExecState != STATE_NOTHING) {
- if (DEBUG) Slog.d(TAG, "Service has new owner " + newOwner
- + " from " + mOwner + " while executing: pkg="
- + mPackage + " service=" + mName + " proc=" + mProc);
- setExecuting(false, 0, now);
- }
- }
- }
- }
- }
-
- public void clearCurrentOwner(Object owner, boolean silently) {
- if (mOwner == owner) {
- mProc.decActiveServices(mName);
- if (mStarted || mBoundState != STATE_NOTHING || mExecState != STATE_NOTHING) {
- long now = SystemClock.uptimeMillis();
- if (mStarted) {
- if (!silently) {
- Slog.wtfStack(TAG, "Service owner " + owner
- + " cleared while started: pkg=" + mPackage + " service="
- + mName + " proc=" + mProc);
- }
- setStarted(false, 0, now);
- }
- if (mBoundState != STATE_NOTHING) {
- if (!silently) {
- Slog.wtfStack(TAG, "Service owner " + owner
- + " cleared while bound: pkg=" + mPackage + " service="
- + mName + " proc=" + mProc);
- }
- setBound(false, 0, now);
- }
- if (mExecState != STATE_NOTHING) {
- if (!silently) {
- Slog.wtfStack(TAG, "Service owner " + owner
- + " cleared while exec: pkg=" + mPackage + " service="
- + mName + " proc=" + mProc);
- }
- setExecuting(false, 0, now);
- }
- }
- mOwner = null;
- }
- }
-
- public boolean isInUse() {
- return mOwner != null || mRestarting;
- }
-
- public boolean isRestarting() {
- return mRestarting;
- }
-
- void add(ServiceState other) {
- addDurations(other);
- mRunCount += other.mRunCount;
- mStartedCount += other.mStartedCount;
- mBoundCount += other.mBoundCount;
- mExecCount += other.mExecCount;
- }
-
- void resetSafely(long now) {
- resetDurationsSafely();
- mRunCount = mRunState != STATE_NOTHING ? 1 : 0;
- mStartedCount = mStartedState != STATE_NOTHING ? 1 : 0;
- mBoundCount = mBoundState != STATE_NOTHING ? 1 : 0;
- mExecCount = mExecState != STATE_NOTHING ? 1 : 0;
- mRunStartTime = mStartedStartTime = mBoundStartTime = mExecStartTime = now;
- }
-
- void writeToParcel(Parcel out, long now) {
- writeDurationsToParcel(out);
- out.writeInt(mRunCount);
- out.writeInt(mStartedCount);
- out.writeInt(mBoundCount);
- out.writeInt(mExecCount);
- }
-
- boolean readFromParcel(Parcel in) {
- if (!readDurationsFromParcel(in)) {
- return false;
- }
- mRunCount = in.readInt();
- mStartedCount = in.readInt();
- mBoundCount = in.readInt();
- mExecCount = in.readInt();
- return true;
- }
-
- void commitStateTime(long now) {
- if (mRunState != STATE_NOTHING) {
- addDuration(SERVICE_RUN + (mRunState*SERVICE_COUNT), now - mRunStartTime);
- mRunStartTime = now;
- }
- if (mStartedState != STATE_NOTHING) {
- addDuration(SERVICE_STARTED + (mStartedState*SERVICE_COUNT),
- now - mStartedStartTime);
- mStartedStartTime = now;
- }
- if (mBoundState != STATE_NOTHING) {
- addDuration(SERVICE_BOUND + (mBoundState*SERVICE_COUNT), now - mBoundStartTime);
- mBoundStartTime = now;
- }
- if (mExecState != STATE_NOTHING) {
- addDuration(SERVICE_EXEC + (mExecState*SERVICE_COUNT), now - mExecStartTime);
- mExecStartTime = now;
- }
- }
-
- private void updateRunning(int memFactor, long now) {
- final int state = (mStartedState != STATE_NOTHING || mBoundState != STATE_NOTHING
- || mExecState != STATE_NOTHING) ? memFactor : STATE_NOTHING;
- if (mRunState != state) {
- if (mRunState != STATE_NOTHING) {
- addDuration(SERVICE_RUN + (mRunState*SERVICE_COUNT),
- now - mRunStartTime);
- } else if (state != STATE_NOTHING) {
- mRunCount++;
- }
- mRunState = state;
- mRunStartTime = now;
- }
- }
-
- public void setStarted(boolean started, int memFactor, long now) {
- if (mOwner == null) {
- Slog.wtf(TAG, "Starting service " + this + " without owner");
- }
- mStarted = started;
- updateStartedState(memFactor, now);
- }
-
- public void setRestarting(boolean restarting, int memFactor, long now) {
- mRestarting = restarting;
- updateStartedState(memFactor, now);
- }
-
- void updateStartedState(int memFactor, long now) {
- final boolean wasStarted = mStartedState != STATE_NOTHING;
- final boolean started = mStarted || mRestarting;
- final int state = started ? memFactor : STATE_NOTHING;
- if (mStartedState != state) {
- if (mStartedState != STATE_NOTHING) {
- addDuration(SERVICE_STARTED + (mStartedState*SERVICE_COUNT),
- now - mStartedStartTime);
- } else if (started) {
- mStartedCount++;
- }
- mStartedState = state;
- mStartedStartTime = now;
- mProc = mProc.pullFixedProc(mPackage);
- if (wasStarted != started) {
- if (started) {
- mProc.incStartedServices(memFactor, now, mName);
- } else {
- mProc.decStartedServices(memFactor, now, mName);
- }
- }
- updateRunning(memFactor, now);
- }
- }
-
- public void setBound(boolean bound, int memFactor, long now) {
- if (mOwner == null) {
- Slog.wtf(TAG, "Binding service " + this + " without owner");
- }
- final int state = bound ? memFactor : STATE_NOTHING;
- if (mBoundState != state) {
- if (mBoundState != STATE_NOTHING) {
- addDuration(SERVICE_BOUND + (mBoundState*SERVICE_COUNT),
- now - mBoundStartTime);
- } else if (bound) {
- mBoundCount++;
- }
- mBoundState = state;
- mBoundStartTime = now;
- updateRunning(memFactor, now);
- }
- }
-
- public void setExecuting(boolean executing, int memFactor, long now) {
- if (mOwner == null) {
- Slog.wtf(TAG, "Executing service " + this + " without owner");
- }
- final int state = executing ? memFactor : STATE_NOTHING;
- if (mExecState != state) {
- if (mExecState != STATE_NOTHING) {
- addDuration(SERVICE_EXEC + (mExecState*SERVICE_COUNT), now - mExecStartTime);
- } else if (executing) {
- mExecCount++;
- }
- mExecState = state;
- mExecStartTime = now;
- updateRunning(memFactor, now);
- }
- }
-
- private long getDuration(int opType, int curState, long startTime, int memFactor,
- long now) {
- int state = opType + (memFactor*SERVICE_COUNT);
- long time = getDuration(state, now);
- if (curState == memFactor) {
- time += now - startTime;
- }
- return time;
- }
-
- public String toString() {
- return "ServiceState{" + Integer.toHexString(System.identityHashCode(this))
- + " " + mName + " pkg=" + mPackage + " proc="
- + Integer.toHexString(System.identityHashCode(this)) + "}";
- }
- }
-
- public static final class PackageState {
- public final ArrayMap<String, ProcessState> mProcesses
- = new ArrayMap<String, ProcessState>();
- public final ArrayMap<String, ServiceState> mServices
- = new ArrayMap<String, ServiceState>();
- public final String mPackageName;
- public final int mUid;
-
- public PackageState(String packageName, int uid) {
- mUid = uid;
- mPackageName = packageName;
- }
- }
-
- public static final class ProcessDataCollection {
- final int[] screenStates;
- final int[] memStates;
- final int[] procStates;
-
- public long totalTime;
- public long numPss;
- public long minPss;
- public long avgPss;
- public long maxPss;
- public long minUss;
- public long avgUss;
- public long maxUss;
-
- public ProcessDataCollection(int[] _screenStates, int[] _memStates, int[] _procStates) {
- screenStates = _screenStates;
- memStates = _memStates;
- procStates = _procStates;
- }
-
- void print(PrintWriter pw, long overallTime, boolean full) {
- if (totalTime > overallTime) {
- pw.print("*");
- }
- printPercent(pw, (double) totalTime / (double) overallTime);
- if (numPss > 0) {
- pw.print(" (");
- DebugUtils.printSizeValue(pw, minPss * 1024);
- pw.print("-");
- DebugUtils.printSizeValue(pw, avgPss * 1024);
- pw.print("-");
- DebugUtils.printSizeValue(pw, maxPss * 1024);
- pw.print("/");
- DebugUtils.printSizeValue(pw, minUss * 1024);
- pw.print("-");
- DebugUtils.printSizeValue(pw, avgUss * 1024);
- pw.print("-");
- DebugUtils.printSizeValue(pw, maxUss * 1024);
- if (full) {
- pw.print(" over ");
- pw.print(numPss);
- }
- pw.print(")");
- }
- }
- }
-
- public static class TotalMemoryUseCollection {
- final int[] screenStates;
- final int[] memStates;
-
- public TotalMemoryUseCollection(int[] _screenStates, int[] _memStates) {
- screenStates = _screenStates;
- memStates = _memStates;
- }
-
- public long totalTime;
- public long[] processStatePss = new long[STATE_COUNT];
- public double[] processStateWeight = new double[STATE_COUNT];
- public long[] processStateTime = new long[STATE_COUNT];
- public int[] processStateSamples = new int[STATE_COUNT];
- public long[] sysMemUsage = new long[SYS_MEM_USAGE_COUNT];
- public double sysMemCachedWeight;
- public double sysMemFreeWeight;
- public double sysMemZRamWeight;
- public double sysMemKernelWeight;
- public double sysMemNativeWeight;
- public int sysMemSamples;
- }
-}
diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index 5726de1..ff680e2 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -243,10 +243,6 @@
return;
}
- // Prevent the Resolver window from becoming the top fullscreen window and thus from taking
- // control of the system bars.
- getWindow().clearFlags(FLAG_LAYOUT_IN_SCREEN|FLAG_LAYOUT_INSET_DECOR);
-
final ResolverDrawerLayout rdl = (ResolverDrawerLayout) findViewById(R.id.contentPanel);
if (rdl != null) {
rdl.setOnDismissedListener(new ResolverDrawerLayout.OnDismissedListener() {
@@ -393,12 +389,7 @@
final DisplayResolveInfo dri = mAdapter.getOtherProfile();
if (dri != null) {
mProfileView.setVisibility(View.VISIBLE);
- final ImageView icon = (ImageView) mProfileView.findViewById(R.id.icon);
- final TextView text = (TextView) mProfileView.findViewById(R.id.text1);
- if (!dri.hasDisplayIcon()) {
- new LoadIconIntoViewTask(dri, icon).execute();
- }
- icon.setImageDrawable(dri.getDisplayIcon());
+ final TextView text = (TextView) mProfileView.findViewById(R.id.profile_button);
text.setText(dri.getDisplayLabel());
} else {
mProfileView.setVisibility(View.GONE);
diff --git a/core/java/com/android/internal/app/SuggestedLocaleAdapter.java b/core/java/com/android/internal/app/SuggestedLocaleAdapter.java
index 98102ea..e2d29e3 100644
--- a/core/java/com/android/internal/app/SuggestedLocaleAdapter.java
+++ b/core/java/com/android/internal/app/SuggestedLocaleAdapter.java
@@ -49,6 +49,7 @@
private static final int TYPE_HEADER_SUGGESTED = 0;
private static final int TYPE_HEADER_ALL_OTHERS = 1;
private static final int TYPE_LOCALE = 2;
+ private static final int MIN_REGIONS_FOR_SUGGESTIONS = 6;
private ArrayList<LocaleStore.LocaleInfo> mLocaleOptions;
private ArrayList<LocaleStore.LocaleInfo> mOriginalLocaleOptions;
@@ -171,7 +172,15 @@
}
private boolean showHeaders() {
- if (mCountryMode) { // never show suggestions in country mode
+ // We don't want to show suggestions for locales with very few regions
+ // (e.g. Romanian, with 2 regions)
+ // So we put a (somewhat) arbitrary limit.
+ //
+ // The initial idea was to make that limit dependent on the screen height.
+ // But that would mean rotating the screen could make the suggestions disappear,
+ // as the number of countries that fits on the screen would be different in portrait
+ // and landscape mode.
+ if (mCountryMode && mLocaleOptions.size() < MIN_REGIONS_FOR_SUGGESTIONS) {
return false;
}
return mSuggestionCount != 0 && mSuggestionCount != mLocaleOptions.size();
diff --git a/core/java/com/android/internal/app/procstats/DumpUtils.java b/core/java/com/android/internal/app/procstats/DumpUtils.java
new file mode 100644
index 0000000..ebedc89
--- /dev/null
+++ b/core/java/com/android/internal/app/procstats/DumpUtils.java
@@ -0,0 +1,369 @@
+/*
+ * Copyright (C) 2013 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.app.procstats;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.SystemClock;
+import android.os.SystemProperties;
+import android.os.UserHandle;
+import android.text.format.DateFormat;
+import android.util.ArrayMap;
+import android.util.ArraySet;
+import android.util.DebugUtils;
+import android.util.Log;
+import android.util.Slog;
+import android.util.SparseArray;
+import android.util.TimeUtils;
+
+import static com.android.internal.app.procstats.ProcessStats.*;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Objects;
+
+/**
+ * Utilities for dumping.
+ */
+public final class DumpUtils {
+ public static final String[] STATE_NAMES = new String[] {
+ "Persist", "Top ", "ImpFg ", "ImpBg ",
+ "Backup ", "HeavyWt", "Service", "ServRst",
+ "Receivr", "Home ",
+ "LastAct", "CchAct ", "CchCAct", "CchEmty"
+ };
+
+ public static final String[] ADJ_SCREEN_NAMES_CSV = new String[] {
+ "off", "on"
+ };
+
+ public static final String[] ADJ_MEM_NAMES_CSV = new String[] {
+ "norm", "mod", "low", "crit"
+ };
+
+ public static final String[] STATE_NAMES_CSV = new String[] {
+ "pers", "top", "impfg", "impbg", "backup", "heavy",
+ "service", "service-rs", "receiver", "home", "lastact",
+ "cch-activity", "cch-aclient", "cch-empty"
+ };
+
+ static final String[] ADJ_SCREEN_TAGS = new String[] {
+ "0", "1"
+ };
+
+ static final String[] ADJ_MEM_TAGS = new String[] {
+ "n", "m", "l", "c"
+ };
+
+ static final String[] STATE_TAGS = new String[] {
+ "p", "t", "f", "b", "u", "w",
+ "s", "x", "r", "h", "l", "a", "c", "e"
+ };
+
+ static final String CSV_SEP = "\t";
+
+ /**
+ * No instantiate
+ */
+ private DumpUtils() {
+ }
+
+ public static void printScreenLabel(PrintWriter pw, int offset) {
+ switch (offset) {
+ case ADJ_NOTHING:
+ pw.print(" ");
+ break;
+ case ADJ_SCREEN_OFF:
+ pw.print("SOff/");
+ break;
+ case ADJ_SCREEN_ON:
+ pw.print("SOn /");
+ break;
+ default:
+ pw.print("????/");
+ break;
+ }
+ }
+
+ public static void printScreenLabelCsv(PrintWriter pw, int offset) {
+ switch (offset) {
+ case ADJ_NOTHING:
+ break;
+ case ADJ_SCREEN_OFF:
+ pw.print(ADJ_SCREEN_NAMES_CSV[0]);
+ break;
+ case ADJ_SCREEN_ON:
+ pw.print(ADJ_SCREEN_NAMES_CSV[1]);
+ break;
+ default:
+ pw.print("???");
+ break;
+ }
+ }
+
+ public static void printMemLabel(PrintWriter pw, int offset, char sep) {
+ switch (offset) {
+ case ADJ_NOTHING:
+ pw.print(" ");
+ if (sep != 0) pw.print(' ');
+ break;
+ case ADJ_MEM_FACTOR_NORMAL:
+ pw.print("Norm");
+ if (sep != 0) pw.print(sep);
+ break;
+ case ADJ_MEM_FACTOR_MODERATE:
+ pw.print("Mod ");
+ if (sep != 0) pw.print(sep);
+ break;
+ case ADJ_MEM_FACTOR_LOW:
+ pw.print("Low ");
+ if (sep != 0) pw.print(sep);
+ break;
+ case ADJ_MEM_FACTOR_CRITICAL:
+ pw.print("Crit");
+ if (sep != 0) pw.print(sep);
+ break;
+ default:
+ pw.print("????");
+ if (sep != 0) pw.print(sep);
+ break;
+ }
+ }
+
+ public static void printMemLabelCsv(PrintWriter pw, int offset) {
+ if (offset >= ADJ_MEM_FACTOR_NORMAL) {
+ if (offset <= ADJ_MEM_FACTOR_CRITICAL) {
+ pw.print(ADJ_MEM_NAMES_CSV[offset]);
+ } else {
+ pw.print("???");
+ }
+ }
+ }
+
+ public static void printPercent(PrintWriter pw, double fraction) {
+ fraction *= 100;
+ if (fraction < 1) {
+ pw.print(String.format("%.2f", fraction));
+ } else if (fraction < 10) {
+ pw.print(String.format("%.1f", fraction));
+ } else {
+ pw.print(String.format("%.0f", fraction));
+ }
+ pw.print("%");
+ }
+
+ public static void printProcStateTag(PrintWriter pw, int state) {
+ state = printArrayEntry(pw, ADJ_SCREEN_TAGS, state, ADJ_SCREEN_MOD*STATE_COUNT);
+ state = printArrayEntry(pw, ADJ_MEM_TAGS, state, STATE_COUNT);
+ printArrayEntry(pw, STATE_TAGS, state, 1);
+ }
+
+ public static void printAdjTag(PrintWriter pw, int state) {
+ state = printArrayEntry(pw, ADJ_SCREEN_TAGS, state, ADJ_SCREEN_MOD);
+ printArrayEntry(pw, ADJ_MEM_TAGS, state, 1);
+ }
+
+ public static void printProcStateTagAndValue(PrintWriter pw, int state, long value) {
+ pw.print(',');
+ printProcStateTag(pw, state);
+ pw.print(':');
+ pw.print(value);
+ }
+
+ public static void printAdjTagAndValue(PrintWriter pw, int state, long value) {
+ pw.print(',');
+ printAdjTag(pw, state);
+ pw.print(':');
+ pw.print(value);
+ }
+
+ public static long dumpSingleTime(PrintWriter pw, String prefix, long[] durations,
+ int curState, long curStartTime, long now) {
+ long totalTime = 0;
+ int printedScreen = -1;
+ for (int iscreen=0; iscreen<ADJ_COUNT; iscreen+=ADJ_SCREEN_MOD) {
+ int printedMem = -1;
+ for (int imem=0; imem<ADJ_MEM_FACTOR_COUNT; imem++) {
+ int state = imem+iscreen;
+ long time = durations[state];
+ String running = "";
+ if (curState == state) {
+ time += now - curStartTime;
+ if (pw != null) {
+ running = " (running)";
+ }
+ }
+ if (time != 0) {
+ if (pw != null) {
+ pw.print(prefix);
+ printScreenLabel(pw, printedScreen != iscreen
+ ? iscreen : STATE_NOTHING);
+ printedScreen = iscreen;
+ printMemLabel(pw, printedMem != imem ? imem : STATE_NOTHING, (char)0);
+ printedMem = imem;
+ pw.print(": ");
+ TimeUtils.formatDuration(time, pw); pw.println(running);
+ }
+ totalTime += time;
+ }
+ }
+ }
+ if (totalTime != 0 && pw != null) {
+ pw.print(prefix);
+ pw.print(" TOTAL: ");
+ TimeUtils.formatDuration(totalTime, pw);
+ pw.println();
+ }
+ return totalTime;
+ }
+
+ public static void dumpAdjTimesCheckin(PrintWriter pw, String sep, long[] durations,
+ int curState, long curStartTime, long now) {
+ for (int iscreen=0; iscreen<ADJ_COUNT; iscreen+=ADJ_SCREEN_MOD) {
+ for (int imem=0; imem<ADJ_MEM_FACTOR_COUNT; imem++) {
+ int state = imem+iscreen;
+ long time = durations[state];
+ if (curState == state) {
+ time += now - curStartTime;
+ }
+ if (time != 0) {
+ printAdjTagAndValue(pw, state, time);
+ }
+ }
+ }
+ }
+
+ private static void dumpStateHeadersCsv(PrintWriter pw, String sep, int[] screenStates,
+ int[] memStates, int[] procStates) {
+ final int NS = screenStates != null ? screenStates.length : 1;
+ final int NM = memStates != null ? memStates.length : 1;
+ final int NP = procStates != null ? procStates.length : 1;
+ for (int is=0; is<NS; is++) {
+ for (int im=0; im<NM; im++) {
+ for (int ip=0; ip<NP; ip++) {
+ pw.print(sep);
+ boolean printed = false;
+ if (screenStates != null && screenStates.length > 1) {
+ printScreenLabelCsv(pw, screenStates[is]);
+ printed = true;
+ }
+ if (memStates != null && memStates.length > 1) {
+ if (printed) {
+ pw.print("-");
+ }
+ printMemLabelCsv(pw, memStates[im]);
+ printed = true;
+ }
+ if (procStates != null && procStates.length > 1) {
+ if (printed) {
+ pw.print("-");
+ }
+ pw.print(STATE_NAMES_CSV[procStates[ip]]);
+ }
+ }
+ }
+ }
+ }
+
+ /*
+ * Doesn't seem to be used.
+ *
+ public static void dumpProcessList(PrintWriter pw, String prefix, ArrayList<ProcessState> procs,
+ int[] screenStates, int[] memStates, int[] procStates, long now) {
+ String innerPrefix = prefix + " ";
+ for (int i=procs.size()-1; i>=0; i--) {
+ ProcessState proc = procs.get(i);
+ pw.print(prefix);
+ pw.print(proc.mName);
+ pw.print(" / ");
+ UserHandle.formatUid(pw, proc.mUid);
+ pw.print(" (");
+ pw.print(proc.durations.getKeyCount());
+ pw.print(" entries)");
+ pw.println(":");
+ proc.dumpProcessState(pw, innerPrefix, screenStates, memStates, procStates, now);
+ if (proc.pssTable.getKeyCount() > 0) {
+ proc.dumpPss(pw, innerPrefix, screenStates, memStates, procStates);
+ }
+ }
+ }
+ */
+
+ public static void dumpProcessSummaryLocked(PrintWriter pw, String prefix,
+ ArrayList<ProcessState> procs, int[] screenStates, int[] memStates, int[] procStates,
+ long now, long totalTime) {
+ for (int i=procs.size()-1; i>=0; i--) {
+ final ProcessState proc = procs.get(i);
+ proc.dumpSummary(pw, prefix, screenStates, memStates, procStates, now, totalTime);
+ }
+ }
+
+ public static void dumpProcessListCsv(PrintWriter pw, ArrayList<ProcessState> procs,
+ boolean sepScreenStates, int[] screenStates, boolean sepMemStates, int[] memStates,
+ boolean sepProcStates, int[] procStates, long now) {
+ pw.print("process");
+ pw.print(CSV_SEP);
+ pw.print("uid");
+ pw.print(CSV_SEP);
+ pw.print("vers");
+ dumpStateHeadersCsv(pw, CSV_SEP, sepScreenStates ? screenStates : null,
+ sepMemStates ? memStates : null,
+ sepProcStates ? procStates : null);
+ pw.println();
+ for (int i=procs.size()-1; i>=0; i--) {
+ ProcessState proc = procs.get(i);
+ pw.print(proc.getName());
+ pw.print(CSV_SEP);
+ UserHandle.formatUid(pw, proc.getUid());
+ pw.print(CSV_SEP);
+ pw.print(proc.getVersion());
+ proc.dumpCsv(pw, sepScreenStates, screenStates, sepMemStates,
+ memStates, sepProcStates, procStates, now);
+ pw.println();
+ }
+ }
+
+ public static int printArrayEntry(PrintWriter pw, String[] array, int value, int mod) {
+ int index = value/mod;
+ if (index >= 0 && index < array.length) {
+ pw.print(array[index]);
+ } else {
+ pw.print('?');
+ }
+ return value - index*mod;
+ }
+
+ public static String collapseString(String pkgName, String itemName) {
+ if (itemName.startsWith(pkgName)) {
+ final int ITEMLEN = itemName.length();
+ final int PKGLEN = pkgName.length();
+ if (ITEMLEN == PKGLEN) {
+ return "";
+ } else if (ITEMLEN >= PKGLEN) {
+ if (itemName.charAt(PKGLEN) == '.') {
+ return itemName.substring(PKGLEN);
+ }
+ }
+ }
+ return itemName;
+ }
+}
diff --git a/core/java/com/android/internal/app/procstats/DurationsTable.java b/core/java/com/android/internal/app/procstats/DurationsTable.java
new file mode 100644
index 0000000..b711ca1
--- /dev/null
+++ b/core/java/com/android/internal/app/procstats/DurationsTable.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2013 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.app.procstats;
+
+/**
+ * Sparse mapping table to store durations of processes, etc running in different
+ * states.
+ */
+public class DurationsTable extends SparseMappingTable.Table {
+ public DurationsTable(SparseMappingTable tableData) {
+ super(tableData);
+ }
+
+ /**
+ * Add all of the durations from the other table into this one.
+ * Resultant durations will be the sum of what is currently in the table
+ * and the new value.
+ */
+ public void addDurations(DurationsTable from) {
+ final int N = from.getKeyCount();
+ for (int i=0; i<N; i++) {
+ final int key = from.getKeyAt(i);
+ this.addDuration(SparseMappingTable.getIdFromKey(key), from.getValue(key));
+ }
+ }
+
+ /**
+ * Add the value into the value stored for the state.
+ *
+ * Resultant duration will be the sum of what is currently in the table
+ * and the new value.
+ */
+ public void addDuration(int state, long value) {
+ final int key = getOrAddKey((byte)state, 1);
+ setValue(key, getValue(key) + value);
+ }
+
+ /*
+ public long getDuration(int state, long now) {
+ final int key = getKey((byte)state);
+ if (key != SparseMappingTable.INVALID_KEY) {
+ return getValue(key);
+ } else {
+ return 0;
+ }
+ }
+ */
+}
+
+
diff --git a/core/java/com/android/internal/app/IProcessStats.aidl b/core/java/com/android/internal/app/procstats/IProcessStats.aidl
similarity index 89%
rename from core/java/com/android/internal/app/IProcessStats.aidl
rename to core/java/com/android/internal/app/procstats/IProcessStats.aidl
index 6fadf2f..44867c7 100644
--- a/core/java/com/android/internal/app/IProcessStats.aidl
+++ b/core/java/com/android/internal/app/procstats/IProcessStats.aidl
@@ -14,11 +14,11 @@
* limitations under the License.
*/
-package com.android.internal.app;
+package com.android.internal.app.procstats;
import android.content.ComponentName;
import android.os.ParcelFileDescriptor;
-import com.android.internal.app.ProcessStats;
+import com.android.internal.app.procstats.ProcessStats;
interface IProcessStats {
byte[] getCurrentStats(out List<ParcelFileDescriptor> historic);
diff --git a/core/java/com/android/internal/app/procstats/ProcessState.java b/core/java/com/android/internal/app/procstats/ProcessState.java
new file mode 100644
index 0000000..80d6070
--- /dev/null
+++ b/core/java/com/android/internal/app/procstats/ProcessState.java
@@ -0,0 +1,1188 @@
+/*
+ * Copyright (C) 2013 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.app.procstats;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.SystemClock;
+import android.os.SystemProperties;
+import android.os.UserHandle;
+import android.text.format.DateFormat;
+import android.util.ArrayMap;
+import android.util.ArraySet;
+import android.util.DebugUtils;
+import android.util.Log;
+import android.util.Slog;
+import android.util.SparseArray;
+import android.util.TimeUtils;
+
+import com.android.internal.app.procstats.ProcessStats;
+import com.android.internal.app.procstats.ProcessStats.PackageState;
+import com.android.internal.app.procstats.ProcessStats.ProcessStateHolder;
+import com.android.internal.app.procstats.ProcessStats.TotalMemoryUseCollection;
+import static com.android.internal.app.procstats.ProcessStats.PSS_SAMPLE_COUNT;
+import static com.android.internal.app.procstats.ProcessStats.PSS_MINIMUM;
+import static com.android.internal.app.procstats.ProcessStats.PSS_AVERAGE;
+import static com.android.internal.app.procstats.ProcessStats.PSS_MAXIMUM;
+import static com.android.internal.app.procstats.ProcessStats.PSS_USS_MINIMUM;
+import static com.android.internal.app.procstats.ProcessStats.PSS_USS_AVERAGE;
+import static com.android.internal.app.procstats.ProcessStats.PSS_USS_MAXIMUM;
+import static com.android.internal.app.procstats.ProcessStats.PSS_COUNT;
+import static com.android.internal.app.procstats.ProcessStats.STATE_NOTHING;
+import static com.android.internal.app.procstats.ProcessStats.STATE_PERSISTENT;
+import static com.android.internal.app.procstats.ProcessStats.STATE_TOP;
+import static com.android.internal.app.procstats.ProcessStats.STATE_IMPORTANT_FOREGROUND;
+import static com.android.internal.app.procstats.ProcessStats.STATE_IMPORTANT_BACKGROUND;
+import static com.android.internal.app.procstats.ProcessStats.STATE_BACKUP;
+import static com.android.internal.app.procstats.ProcessStats.STATE_HEAVY_WEIGHT;
+import static com.android.internal.app.procstats.ProcessStats.STATE_SERVICE;
+import static com.android.internal.app.procstats.ProcessStats.STATE_SERVICE_RESTARTING;
+import static com.android.internal.app.procstats.ProcessStats.STATE_RECEIVER;
+import static com.android.internal.app.procstats.ProcessStats.STATE_HOME;
+import static com.android.internal.app.procstats.ProcessStats.STATE_LAST_ACTIVITY;
+import static com.android.internal.app.procstats.ProcessStats.STATE_CACHED_ACTIVITY;
+import static com.android.internal.app.procstats.ProcessStats.STATE_CACHED_ACTIVITY_CLIENT;
+import static com.android.internal.app.procstats.ProcessStats.STATE_CACHED_EMPTY;
+import static com.android.internal.app.procstats.ProcessStats.STATE_COUNT;
+
+import dalvik.system.VMRuntime;
+import libcore.util.EmptyArray;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Objects;
+
+public final class ProcessState {
+ private static final String TAG = "ProcessStats";
+ private static final boolean DEBUG = false;
+ private static final boolean DEBUG_PARCEL = false;
+
+ // Map from process states to the states we track.
+ private static final int[] PROCESS_STATE_TO_STATE = new int[] {
+ STATE_PERSISTENT, // ActivityManager.PROCESS_STATE_PERSISTENT
+ STATE_PERSISTENT, // ActivityManager.PROCESS_STATE_PERSISTENT_UI
+ STATE_TOP, // ActivityManager.PROCESS_STATE_TOP
+ STATE_IMPORTANT_FOREGROUND, // ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE
+ STATE_IMPORTANT_FOREGROUND, // ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE
+ STATE_TOP, // ActivityManager.PROCESS_STATE_TOP_SLEEPING
+ STATE_IMPORTANT_FOREGROUND, // ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND
+ STATE_IMPORTANT_BACKGROUND, // ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND
+ STATE_BACKUP, // ActivityManager.PROCESS_STATE_BACKUP
+ STATE_HEAVY_WEIGHT, // ActivityManager.PROCESS_STATE_HEAVY_WEIGHT
+ STATE_SERVICE, // ActivityManager.PROCESS_STATE_SERVICE
+ STATE_RECEIVER, // ActivityManager.PROCESS_STATE_RECEIVER
+ STATE_HOME, // ActivityManager.PROCESS_STATE_HOME
+ STATE_LAST_ACTIVITY, // ActivityManager.PROCESS_STATE_LAST_ACTIVITY
+ STATE_CACHED_ACTIVITY, // ActivityManager.PROCESS_STATE_CACHED_ACTIVITY
+ STATE_CACHED_ACTIVITY_CLIENT, // ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT
+ STATE_CACHED_EMPTY, // ActivityManager.PROCESS_STATE_CACHED_EMPTY
+ };
+
+ public static final Comparator<ProcessState> COMPARATOR = new Comparator<ProcessState>() {
+ @Override
+ public int compare(ProcessState lhs, ProcessState rhs) {
+ if (lhs.mTmpTotalTime < rhs.mTmpTotalTime) {
+ return -1;
+ } else if (lhs.mTmpTotalTime > rhs.mTmpTotalTime) {
+ return 1;
+ }
+ return 0;
+ }
+ };
+
+ static class PssAggr {
+ long pss = 0;
+ long samples = 0;
+
+ void add(long newPss, long newSamples) {
+ pss = (long)( (pss*(double)samples) + (newPss*(double)newSamples) )
+ / (samples+newSamples);
+ samples += newSamples;
+ }
+ }
+
+ // Used by reset to count rather than storing extra maps. Be careful.
+ public int tmpNumInUse;
+ public ProcessState tmpFoundSubProc;
+
+ private final ProcessStats mStats;
+ private final String mName;
+ private final String mPackage;
+ private final int mUid;
+ private final int mVersion;
+ private final DurationsTable mDurations;
+ private final PssTable mPssTable;
+
+ private ProcessState mCommonProcess;
+ private int mCurState = STATE_NOTHING;
+ private long mStartTime;
+
+ private int mLastPssState = STATE_NOTHING;
+ private long mLastPssTime;
+
+ private boolean mActive;
+ private int mNumActiveServices;
+ private int mNumStartedServices;
+
+ private int mNumExcessiveWake;
+ private int mNumExcessiveCpu;
+
+ private int mNumCachedKill;
+ private long mMinCachedKillPss;
+ private long mAvgCachedKillPss;
+ private long mMaxCachedKillPss;
+
+ private boolean mMultiPackage;
+ private boolean mDead;
+
+ // Set in computeProcessTimeLocked and used by COMPARATOR to sort. Be careful.
+ private long mTmpTotalTime;
+
+ /**
+ * Create a new top-level process state, for the initial case where there is only
+ * a single package running in a process. The initial state is not running.
+ */
+ public ProcessState(ProcessStats processStats, String pkg, int uid, int vers, String name) {
+ mStats = processStats;
+ mName = name;
+ mCommonProcess = this;
+ mPackage = pkg;
+ mUid = uid;
+ mVersion = vers;
+ mDurations = new DurationsTable(processStats.mTableData);
+ mPssTable = new PssTable(processStats.mTableData);
+ }
+
+ /**
+ * Create a new per-package process state for an existing top-level process
+ * state. The current running state of the top-level process is also copied,
+ * marked as started running at 'now'.
+ */
+ public ProcessState(ProcessState commonProcess, String pkg, int uid, int vers, String name,
+ long now) {
+ mStats = commonProcess.mStats;
+ mName = name;
+ mCommonProcess = commonProcess;
+ mPackage = pkg;
+ mUid = uid;
+ mVersion = vers;
+ mCurState = commonProcess.mCurState;
+ mStartTime = now;
+ mDurations = new DurationsTable(commonProcess.mStats.mTableData);
+ mPssTable = new PssTable(commonProcess.mStats.mTableData);
+ }
+
+ public ProcessState clone(long now) {
+ ProcessState pnew = new ProcessState(this, mPackage, mUid, mVersion, mName, now);
+ pnew.mDurations.addDurations(mDurations);
+ pnew.mPssTable.copyFrom(mPssTable, PSS_COUNT);
+ pnew.mNumExcessiveWake = mNumExcessiveWake;
+ pnew.mNumExcessiveCpu = mNumExcessiveCpu;
+ pnew.mNumCachedKill = mNumCachedKill;
+ pnew.mMinCachedKillPss = mMinCachedKillPss;
+ pnew.mAvgCachedKillPss = mAvgCachedKillPss;
+ pnew.mMaxCachedKillPss = mMaxCachedKillPss;
+ pnew.mActive = mActive;
+ pnew.mNumActiveServices = mNumActiveServices;
+ pnew.mNumStartedServices = mNumStartedServices;
+ return pnew;
+ }
+
+ public String getName() {
+ return mName;
+ }
+
+ public ProcessState getCommonProcess() {
+ return mCommonProcess;
+ }
+
+ /**
+ * Say that we are not part of a shared process, so mCommonProcess = this.
+ */
+ public void makeStandalone() {
+ mCommonProcess = this;
+ }
+
+ public String getPackage() {
+ return mPackage;
+ }
+
+ public int getUid() {
+ return mUid;
+ }
+
+ public int getVersion() {
+ return mVersion;
+ }
+
+ public boolean isMultiPackage() {
+ return mMultiPackage;
+ }
+
+ public void setMultiPackage(boolean val) {
+ mMultiPackage = val;
+ }
+
+ public int getDurationsBucketCount() {
+ return mDurations.getKeyCount();
+ }
+
+ public void add(ProcessState other) {
+ mDurations.addDurations(other.mDurations);
+ mPssTable.mergeStats(other.mPssTable);
+ mNumExcessiveWake += other.mNumExcessiveWake;
+ mNumExcessiveCpu += other.mNumExcessiveCpu;
+ if (other.mNumCachedKill > 0) {
+ addCachedKill(other.mNumCachedKill, other.mMinCachedKillPss,
+ other.mAvgCachedKillPss, other.mMaxCachedKillPss);
+ }
+ }
+
+ public void resetSafely(long now) {
+ mDurations.resetTable();
+ mPssTable.resetTable();
+ mStartTime = now;
+ mLastPssState = STATE_NOTHING;
+ mLastPssTime = 0;
+ mNumExcessiveWake = 0;
+ mNumExcessiveCpu = 0;
+ mNumCachedKill = 0;
+ mMinCachedKillPss = mAvgCachedKillPss = mMaxCachedKillPss = 0;
+ }
+
+ public void makeDead() {
+ mDead = true;
+ }
+
+ private void ensureNotDead() {
+ if (!mDead) {
+ return;
+ }
+ Slog.wtfStack(TAG, "ProcessState dead: name=" + mName
+ + " pkg=" + mPackage + " uid=" + mUid + " common.name=" + mCommonProcess.mName);
+ }
+
+ public void writeToParcel(Parcel out, long now) {
+ out.writeInt(mMultiPackage ? 1 : 0);
+ mDurations.writeToParcel(out);
+ mPssTable.writeToParcel(out);
+ out.writeInt(mNumExcessiveWake);
+ out.writeInt(mNumExcessiveCpu);
+ out.writeInt(mNumCachedKill);
+ if (mNumCachedKill > 0) {
+ out.writeLong(mMinCachedKillPss);
+ out.writeLong(mAvgCachedKillPss);
+ out.writeLong(mMaxCachedKillPss);
+ }
+ }
+
+ public boolean readFromParcel(Parcel in, boolean fully) {
+ boolean multiPackage = in.readInt() != 0;
+ if (fully) {
+ mMultiPackage = multiPackage;
+ }
+ if (DEBUG_PARCEL) Slog.d(TAG, "Reading durations table...");
+ if (!mDurations.readFromParcel(in)) {
+ return false;
+ }
+ if (DEBUG_PARCEL) Slog.d(TAG, "Reading pss table...");
+ if (!mPssTable.readFromParcel(in)) {
+ return false;
+ }
+ mNumExcessiveWake = in.readInt();
+ mNumExcessiveCpu = in.readInt();
+ mNumCachedKill = in.readInt();
+ if (mNumCachedKill > 0) {
+ mMinCachedKillPss = in.readLong();
+ mAvgCachedKillPss = in.readLong();
+ mMaxCachedKillPss = in.readLong();
+ } else {
+ mMinCachedKillPss = mAvgCachedKillPss = mMaxCachedKillPss = 0;
+ }
+ return true;
+ }
+
+ public void makeActive() {
+ ensureNotDead();
+ mActive = true;
+ }
+
+ public void makeInactive() {
+ mActive = false;
+ }
+
+ public boolean isInUse() {
+ return mActive || mNumActiveServices > 0 || mNumStartedServices > 0
+ || mCurState != STATE_NOTHING;
+ }
+
+ public boolean isActive() {
+ return mActive;
+ }
+
+ public boolean hasAnyData() {
+ return !(mDurations.getKeyCount() == 0
+ && mCurState == STATE_NOTHING
+ && mPssTable.getKeyCount() == 0);
+ }
+
+ /**
+ * Update the current state of the given list of processes.
+ *
+ * @param state Current ActivityManager.PROCESS_STATE_*
+ * @param memFactor Current mem factor constant.
+ * @param now Current time.
+ * @param pkgList Processes to update.
+ */
+ public void setState(int state, int memFactor, long now,
+ ArrayMap<String, ProcessStateHolder> pkgList) {
+ if (state < 0) {
+ state = mNumStartedServices > 0
+ ? (STATE_SERVICE_RESTARTING+(memFactor*STATE_COUNT)) : STATE_NOTHING;
+ } else {
+ state = PROCESS_STATE_TO_STATE[state] + (memFactor*STATE_COUNT);
+ }
+
+ // First update the common process.
+ mCommonProcess.setState(state, now);
+
+ // If the common process is not multi-package, there is nothing else to do.
+ if (!mCommonProcess.mMultiPackage) {
+ return;
+ }
+
+ if (pkgList != null) {
+ for (int ip=pkgList.size()-1; ip>=0; ip--) {
+ pullFixedProc(pkgList, ip).setState(state, now);
+ }
+ }
+ }
+
+ public void setState(int state, long now) {
+ ensureNotDead();
+ if (mCurState != state) {
+ //Slog.i(TAG, "Setting state in " + mName + "/" + mPackage + ": " + state);
+ commitStateTime(now);
+ mCurState = state;
+ }
+ }
+
+ public void commitStateTime(long now) {
+ if (mCurState != STATE_NOTHING) {
+ long dur = now - mStartTime;
+ if (dur > 0) {
+ mDurations.addDuration(mCurState, dur);
+ }
+ }
+ mStartTime = now;
+ }
+
+ public void incActiveServices(String serviceName) {
+ if (DEBUG && "".equals(mName)) {
+ RuntimeException here = new RuntimeException("here");
+ here.fillInStackTrace();
+ Slog.d(TAG, "incActiveServices: " + this + " service=" + serviceName
+ + " to " + (mNumActiveServices+1), here);
+ }
+ if (mCommonProcess != this) {
+ mCommonProcess.incActiveServices(serviceName);
+ }
+ mNumActiveServices++;
+ }
+
+ public void decActiveServices(String serviceName) {
+ if (DEBUG && "".equals(mName)) {
+ RuntimeException here = new RuntimeException("here");
+ here.fillInStackTrace();
+ Slog.d(TAG, "decActiveServices: " + this + " service=" + serviceName
+ + " to " + (mNumActiveServices-1), here);
+ }
+ if (mCommonProcess != this) {
+ mCommonProcess.decActiveServices(serviceName);
+ }
+ mNumActiveServices--;
+ if (mNumActiveServices < 0) {
+ Slog.wtfStack(TAG, "Proc active services underrun: pkg=" + mPackage
+ + " uid=" + mUid + " proc=" + mName + " service=" + serviceName);
+ mNumActiveServices = 0;
+ }
+ }
+
+ public void incStartedServices(int memFactor, long now, String serviceName) {
+ if (false) {
+ RuntimeException here = new RuntimeException("here");
+ here.fillInStackTrace();
+ Slog.d(TAG, "incStartedServices: " + this + " service=" + serviceName
+ + " to " + (mNumStartedServices+1), here);
+ }
+ if (mCommonProcess != this) {
+ mCommonProcess.incStartedServices(memFactor, now, serviceName);
+ }
+ mNumStartedServices++;
+ if (mNumStartedServices == 1 && mCurState == STATE_NOTHING) {
+ setState(STATE_SERVICE_RESTARTING + (memFactor*STATE_COUNT), now);
+ }
+ }
+
+ public void decStartedServices(int memFactor, long now, String serviceName) {
+ if (false) {
+ RuntimeException here = new RuntimeException("here");
+ here.fillInStackTrace();
+ Slog.d(TAG, "decActiveServices: " + this + " service=" + serviceName
+ + " to " + (mNumStartedServices-1), here);
+ }
+ if (mCommonProcess != this) {
+ mCommonProcess.decStartedServices(memFactor, now, serviceName);
+ }
+ mNumStartedServices--;
+ if (mNumStartedServices == 0 && (mCurState%STATE_COUNT) == STATE_SERVICE_RESTARTING) {
+ setState(STATE_NOTHING, now);
+ } else if (mNumStartedServices < 0) {
+ Slog.wtfStack(TAG, "Proc started services underrun: pkg="
+ + mPackage + " uid=" + mUid + " name=" + mName);
+ mNumStartedServices = 0;
+ }
+ }
+
+ public void addPss(long pss, long uss, boolean always,
+ ArrayMap<String, ProcessStateHolder> pkgList) {
+ ensureNotDead();
+ if (!always) {
+ if (mLastPssState == mCurState && SystemClock.uptimeMillis()
+ < (mLastPssTime+(30*1000))) {
+ return;
+ }
+ }
+ mLastPssState = mCurState;
+ mLastPssTime = SystemClock.uptimeMillis();
+ if (mCurState != STATE_NOTHING) {
+ // First update the common process.
+ mCommonProcess.mPssTable.mergeStats(mCurState, 1, pss, pss, pss, uss, uss, uss);
+
+ // If the common process is not multi-package, there is nothing else to do.
+ if (!mCommonProcess.mMultiPackage) {
+ return;
+ }
+
+ if (pkgList != null) {
+ for (int ip=pkgList.size()-1; ip>=0; ip--) {
+ pullFixedProc(pkgList, ip).mPssTable.mergeStats(mCurState, 1,
+ pss, pss, pss, uss, uss, uss);
+ }
+ }
+ }
+ }
+
+ public void reportExcessiveWake(ArrayMap<String, ProcessStateHolder> pkgList) {
+ ensureNotDead();
+ mCommonProcess.mNumExcessiveWake++;
+ if (!mCommonProcess.mMultiPackage) {
+ return;
+ }
+
+ for (int ip=pkgList.size()-1; ip>=0; ip--) {
+ pullFixedProc(pkgList, ip).mNumExcessiveWake++;
+ }
+ }
+
+ public void reportExcessiveCpu(ArrayMap<String, ProcessStateHolder> pkgList) {
+ ensureNotDead();
+ mCommonProcess.mNumExcessiveCpu++;
+ if (!mCommonProcess.mMultiPackage) {
+ return;
+ }
+
+ for (int ip=pkgList.size()-1; ip>=0; ip--) {
+ pullFixedProc(pkgList, ip).mNumExcessiveCpu++;
+ }
+ }
+
+ private void addCachedKill(int num, long minPss, long avgPss, long maxPss) {
+ if (mNumCachedKill <= 0) {
+ mNumCachedKill = num;
+ mMinCachedKillPss = minPss;
+ mAvgCachedKillPss = avgPss;
+ mMaxCachedKillPss = maxPss;
+ } else {
+ if (minPss < mMinCachedKillPss) {
+ mMinCachedKillPss = minPss;
+ }
+ if (maxPss > mMaxCachedKillPss) {
+ mMaxCachedKillPss = maxPss;
+ }
+ mAvgCachedKillPss = (long)( ((mAvgCachedKillPss*(double)mNumCachedKill) + avgPss)
+ / (mNumCachedKill+num) );
+ mNumCachedKill += num;
+ }
+ }
+
+ public void reportCachedKill(ArrayMap<String, ProcessStateHolder> pkgList, long pss) {
+ ensureNotDead();
+ mCommonProcess.addCachedKill(1, pss, pss, pss);
+ if (!mCommonProcess.mMultiPackage) {
+ return;
+ }
+
+ for (int ip=pkgList.size()-1; ip>=0; ip--) {
+ pullFixedProc(pkgList, ip).addCachedKill(1, pss, pss, pss);
+ }
+ }
+
+ public ProcessState pullFixedProc(String pkgName) {
+ if (mMultiPackage) {
+ // The array map is still pointing to a common process state
+ // that is now shared across packages. Update it to point to
+ // the new per-package state.
+ SparseArray<PackageState> vpkg = mStats.mPackages.get(pkgName, mUid);
+ if (vpkg == null) {
+ throw new IllegalStateException("Didn't find package " + pkgName
+ + " / " + mUid);
+ }
+ PackageState pkg = vpkg.get(mVersion);
+ if (pkg == null) {
+ throw new IllegalStateException("Didn't find package " + pkgName
+ + " / " + mUid + " vers " + mVersion);
+ }
+ ProcessState proc = pkg.mProcesses.get(mName);
+ if (proc == null) {
+ throw new IllegalStateException("Didn't create per-package process "
+ + mName + " in pkg " + pkgName + " / " + mUid + " vers " + mVersion);
+ }
+ return proc;
+ }
+ return this;
+ }
+
+ private ProcessState pullFixedProc(ArrayMap<String, ProcessStateHolder> pkgList,
+ int index) {
+ ProcessStateHolder holder = pkgList.valueAt(index);
+ ProcessState proc = holder.state;
+ if (mDead && proc.mCommonProcess != proc) {
+ // Somehow we are contining to use a process state that is dead, because
+ // it was not being told it was active during the last commit. We can recover
+ // from this by generating a fresh new state, but this is bad because we
+ // are losing whatever data we had in the old process state.
+ Log.wtf(TAG, "Pulling dead proc: name=" + mName + " pkg=" + mPackage
+ + " uid=" + mUid + " common.name=" + mCommonProcess.mName);
+ proc = mStats.getProcessStateLocked(proc.mPackage, proc.mUid, proc.mVersion,
+ proc.mName);
+ }
+ if (proc.mMultiPackage) {
+ // The array map is still pointing to a common process state
+ // that is now shared across packages. Update it to point to
+ // the new per-package state.
+ SparseArray<PackageState> vpkg = mStats.mPackages.get(pkgList.keyAt(index),
+ proc.mUid);
+ if (vpkg == null) {
+ throw new IllegalStateException("No existing package "
+ + pkgList.keyAt(index) + "/" + proc.mUid
+ + " for multi-proc " + proc.mName);
+ }
+ PackageState pkg = vpkg.get(proc.mVersion);
+ if (pkg == null) {
+ throw new IllegalStateException("No existing package "
+ + pkgList.keyAt(index) + "/" + proc.mUid
+ + " for multi-proc " + proc.mName + " version " + proc.mVersion);
+ }
+ String savedName = proc.mName;
+ proc = pkg.mProcesses.get(proc.mName);
+ if (proc == null) {
+ throw new IllegalStateException("Didn't create per-package process "
+ + savedName + " in pkg " + pkg.mPackageName + "/" + pkg.mUid);
+ }
+ holder.state = proc;
+ }
+ return proc;
+ }
+
+ public long getDuration(int state, long now) {
+ long time = mDurations.getValueForId((byte)state);
+ if (mCurState == state) {
+ time += now - mStartTime;
+ }
+ return time;
+ }
+
+ public long getPssSampleCount(int state) {
+ return mPssTable.getValueForId((byte)state, PSS_SAMPLE_COUNT);
+ }
+
+ public long getPssMinimum(int state) {
+ return mPssTable.getValueForId((byte)state, PSS_MINIMUM);
+ }
+
+ public long getPssAverage(int state) {
+ return mPssTable.getValueForId((byte)state, PSS_AVERAGE);
+ }
+
+ public long getPssMaximum(int state) {
+ return mPssTable.getValueForId((byte)state, PSS_MAXIMUM);
+ }
+
+ public long getPssUssMinimum(int state) {
+ return mPssTable.getValueForId((byte)state, PSS_USS_MINIMUM);
+ }
+
+ public long getPssUssAverage(int state) {
+ return mPssTable.getValueForId((byte)state, PSS_USS_AVERAGE);
+ }
+
+ public long getPssUssMaximum(int state) {
+ return mPssTable.getValueForId((byte)state, PSS_USS_MAXIMUM);
+ }
+
+ /**
+ * Sums up the PSS data and adds it to 'data'.
+ *
+ * @param data The aggregate data is added here.
+ * @param now SystemClock.uptimeMillis()
+ */
+ public void aggregatePss(TotalMemoryUseCollection data, long now) {
+ final PssAggr fgPss = new PssAggr();
+ final PssAggr bgPss = new PssAggr();
+ final PssAggr cachedPss = new PssAggr();
+ boolean havePss = false;
+ for (int i=0; i<mDurations.getKeyCount(); i++) {
+ final int key = mDurations.getKeyAt(i);
+ int type = SparseMappingTable.getIdFromKey(key);
+ int procState = type % STATE_COUNT;
+ long samples = getPssSampleCount(type);
+ if (samples > 0) {
+ long avg = getPssAverage(type);
+ havePss = true;
+ if (procState <= STATE_IMPORTANT_FOREGROUND) {
+ fgPss.add(avg, samples);
+ } else if (procState <= STATE_RECEIVER) {
+ bgPss.add(avg, samples);
+ } else {
+ cachedPss.add(avg, samples);
+ }
+ }
+ }
+ if (!havePss) {
+ return;
+ }
+ boolean fgHasBg = false;
+ boolean fgHasCached = false;
+ boolean bgHasCached = false;
+ if (fgPss.samples < 3 && bgPss.samples > 0) {
+ fgHasBg = true;
+ fgPss.add(bgPss.pss, bgPss.samples);
+ }
+ if (fgPss.samples < 3 && cachedPss.samples > 0) {
+ fgHasCached = true;
+ fgPss.add(cachedPss.pss, cachedPss.samples);
+ }
+ if (bgPss.samples < 3 && cachedPss.samples > 0) {
+ bgHasCached = true;
+ bgPss.add(cachedPss.pss, cachedPss.samples);
+ }
+ if (bgPss.samples < 3 && !fgHasBg && fgPss.samples > 0) {
+ bgPss.add(fgPss.pss, fgPss.samples);
+ }
+ if (cachedPss.samples < 3 && !bgHasCached && bgPss.samples > 0) {
+ cachedPss.add(bgPss.pss, bgPss.samples);
+ }
+ if (cachedPss.samples < 3 && !fgHasCached && fgPss.samples > 0) {
+ cachedPss.add(fgPss.pss, fgPss.samples);
+ }
+ for (int i=0; i<mDurations.getKeyCount(); i++) {
+ final int key = mDurations.getKeyAt(i);
+ final int type = SparseMappingTable.getIdFromKey(key);
+ long time = mDurations.getValue(key);
+ if (mCurState == type) {
+ time += now - mStartTime;
+ }
+ final int procState = type % STATE_COUNT;
+ data.processStateTime[procState] += time;
+ long samples = getPssSampleCount(type);
+ long avg;
+ if (samples > 0) {
+ avg = getPssAverage(type);
+ } else if (procState <= STATE_IMPORTANT_FOREGROUND) {
+ samples = fgPss.samples;
+ avg = fgPss.pss;
+ } else if (procState <= STATE_RECEIVER) {
+ samples = bgPss.samples;
+ avg = bgPss.pss;
+ } else {
+ samples = cachedPss.samples;
+ avg = cachedPss.pss;
+ }
+ double newAvg = ( (data.processStatePss[procState]
+ * (double)data.processStateSamples[procState])
+ + (avg*(double)samples)
+ ) / (data.processStateSamples[procState]+samples);
+ data.processStatePss[procState] = (long)newAvg;
+ data.processStateSamples[procState] += samples;
+ data.processStateWeight[procState] += avg * (double)time;
+ }
+ }
+
+ public long computeProcessTimeLocked(int[] screenStates, int[] memStates,
+ int[] procStates, long now) {
+ long totalTime = 0;
+ for (int is=0; is<screenStates.length; is++) {
+ for (int im=0; im<memStates.length; im++) {
+ for (int ip=0; ip<procStates.length; ip++) {
+ int bucket = ((screenStates[is] + memStates[im]) * STATE_COUNT)
+ + procStates[ip];
+ totalTime += getDuration(bucket, now);
+ }
+ }
+ }
+ mTmpTotalTime = totalTime;
+ return totalTime;
+ }
+
+ public void dumpSummary(PrintWriter pw, String prefix,
+ int[] screenStates, int[] memStates, int[] procStates,
+ long now, long totalTime) {
+ pw.print(prefix);
+ pw.print("* ");
+ pw.print(mName);
+ pw.print(" / ");
+ UserHandle.formatUid(pw, mUid);
+ pw.print(" / v");
+ pw.print(mVersion);
+ pw.println(":");
+ dumpProcessSummaryDetails(pw, prefix, " TOTAL: ", screenStates, memStates,
+ procStates, now, totalTime, true);
+ dumpProcessSummaryDetails(pw, prefix, " Persistent: ", screenStates, memStates,
+ new int[] { STATE_PERSISTENT }, now, totalTime, true);
+ dumpProcessSummaryDetails(pw, prefix, " Top: ", screenStates, memStates,
+ new int[] {STATE_TOP}, now, totalTime, true);
+ dumpProcessSummaryDetails(pw, prefix, " Imp Fg: ", screenStates, memStates,
+ new int[] { STATE_IMPORTANT_FOREGROUND }, now, totalTime, true);
+ dumpProcessSummaryDetails(pw, prefix, " Imp Bg: ", screenStates, memStates,
+ new int[] {STATE_IMPORTANT_BACKGROUND}, now, totalTime, true);
+ dumpProcessSummaryDetails(pw, prefix, " Backup: ", screenStates, memStates,
+ new int[] {STATE_BACKUP}, now, totalTime, true);
+ dumpProcessSummaryDetails(pw, prefix, " Heavy Wgt: ", screenStates, memStates,
+ new int[] {STATE_HEAVY_WEIGHT}, now, totalTime, true);
+ dumpProcessSummaryDetails(pw, prefix, " Service: ", screenStates, memStates,
+ new int[] {STATE_SERVICE}, now, totalTime, true);
+ dumpProcessSummaryDetails(pw, prefix, " Service Rs: ", screenStates, memStates,
+ new int[] {STATE_SERVICE_RESTARTING}, now, totalTime, true);
+ dumpProcessSummaryDetails(pw, prefix, " Receiver: ", screenStates, memStates,
+ new int[] {STATE_RECEIVER}, now, totalTime, true);
+ dumpProcessSummaryDetails(pw, prefix, " (Home): ", screenStates, memStates,
+ new int[] {STATE_HOME}, now, totalTime, true);
+ dumpProcessSummaryDetails(pw, prefix, " (Last Act): ", screenStates, memStates,
+ new int[] {STATE_LAST_ACTIVITY}, now, totalTime, true);
+ dumpProcessSummaryDetails(pw, prefix, " (Cached): ", screenStates, memStates,
+ new int[] {STATE_CACHED_ACTIVITY, STATE_CACHED_ACTIVITY_CLIENT,
+ STATE_CACHED_EMPTY}, now, totalTime, true);
+ }
+
+ public void dumpProcessState(PrintWriter pw, String prefix,
+ int[] screenStates, int[] memStates, int[] procStates, long now) {
+ long totalTime = 0;
+ int printedScreen = -1;
+ for (int is=0; is<screenStates.length; is++) {
+ int printedMem = -1;
+ for (int im=0; im<memStates.length; im++) {
+ for (int ip=0; ip<procStates.length; ip++) {
+ final int iscreen = screenStates[is];
+ final int imem = memStates[im];
+ final int bucket = ((iscreen + imem) * STATE_COUNT) + procStates[ip];
+ long time = mDurations.getValueForId((byte)bucket);
+ String running = "";
+ if (mCurState == bucket) {
+ running = " (running)";
+ }
+ if (time != 0) {
+ pw.print(prefix);
+ if (screenStates.length > 1) {
+ DumpUtils.printScreenLabel(pw, printedScreen != iscreen
+ ? iscreen : STATE_NOTHING);
+ printedScreen = iscreen;
+ }
+ if (memStates.length > 1) {
+ DumpUtils.printMemLabel(pw,
+ printedMem != imem ? imem : STATE_NOTHING, '/');
+ printedMem = imem;
+ }
+ pw.print(DumpUtils.STATE_NAMES[procStates[ip]]); pw.print(": ");
+ TimeUtils.formatDuration(time, pw); pw.println(running);
+ totalTime += time;
+ }
+ }
+ }
+ }
+ if (totalTime != 0) {
+ pw.print(prefix);
+ if (screenStates.length > 1) {
+ DumpUtils.printScreenLabel(pw, STATE_NOTHING);
+ }
+ if (memStates.length > 1) {
+ DumpUtils.printMemLabel(pw, STATE_NOTHING, '/');
+ }
+ pw.print("TOTAL : ");
+ TimeUtils.formatDuration(totalTime, pw);
+ pw.println();
+ }
+ }
+
+ public void dumpPss(PrintWriter pw, String prefix,
+ int[] screenStates, int[] memStates, int[] procStates) {
+ boolean printedHeader = false;
+ int printedScreen = -1;
+ for (int is=0; is<screenStates.length; is++) {
+ int printedMem = -1;
+ for (int im=0; im<memStates.length; im++) {
+ for (int ip=0; ip<procStates.length; ip++) {
+ final int iscreen = screenStates[is];
+ final int imem = memStates[im];
+ final int bucket = ((iscreen + imem) * STATE_COUNT) + procStates[ip];
+ long count = getPssSampleCount(bucket);
+ if (count > 0) {
+ if (!printedHeader) {
+ pw.print(prefix);
+ pw.print("PSS/USS (");
+ pw.print(mPssTable.getKeyCount());
+ pw.println(" entries):");
+ printedHeader = true;
+ }
+ pw.print(prefix);
+ pw.print(" ");
+ if (screenStates.length > 1) {
+ DumpUtils.printScreenLabel(pw,
+ printedScreen != iscreen ? iscreen : STATE_NOTHING);
+ printedScreen = iscreen;
+ }
+ if (memStates.length > 1) {
+ DumpUtils.printMemLabel(pw,
+ printedMem != imem ? imem : STATE_NOTHING, '/');
+ printedMem = imem;
+ }
+ pw.print(DumpUtils.STATE_NAMES[procStates[ip]]); pw.print(": ");
+ pw.print(count);
+ pw.print(" samples ");
+ DebugUtils.printSizeValue(pw, getPssMinimum(bucket) * 1024);
+ pw.print(" ");
+ DebugUtils.printSizeValue(pw, getPssAverage(bucket) * 1024);
+ pw.print(" ");
+ DebugUtils.printSizeValue(pw, getPssMaximum(bucket) * 1024);
+ pw.print(" / ");
+ DebugUtils.printSizeValue(pw, getPssUssMinimum(bucket) * 1024);
+ pw.print(" ");
+ DebugUtils.printSizeValue(pw, getPssUssAverage(bucket) * 1024);
+ pw.print(" ");
+ DebugUtils.printSizeValue(pw, getPssUssMaximum(bucket) * 1024);
+ pw.println();
+ }
+ }
+ }
+ }
+ if (mNumExcessiveWake != 0) {
+ pw.print(prefix); pw.print("Killed for excessive wake locks: ");
+ pw.print(mNumExcessiveWake); pw.println(" times");
+ }
+ if (mNumExcessiveCpu != 0) {
+ pw.print(prefix); pw.print("Killed for excessive CPU use: ");
+ pw.print(mNumExcessiveCpu); pw.println(" times");
+ }
+ if (mNumCachedKill != 0) {
+ pw.print(prefix); pw.print("Killed from cached state: ");
+ pw.print(mNumCachedKill); pw.print(" times from pss ");
+ DebugUtils.printSizeValue(pw, mMinCachedKillPss * 1024); pw.print("-");
+ DebugUtils.printSizeValue(pw, mAvgCachedKillPss * 1024); pw.print("-");
+ DebugUtils.printSizeValue(pw, mMaxCachedKillPss * 1024); pw.println();
+ }
+ }
+
+ private void dumpProcessSummaryDetails(PrintWriter pw, String prefix,
+ String label, int[] screenStates, int[] memStates, int[] procStates,
+ long now, long totalTime, boolean full) {
+ ProcessStats.ProcessDataCollection totals = new ProcessStats.ProcessDataCollection(
+ screenStates, memStates, procStates);
+ computeProcessData(totals, now);
+ final double percentage = (double) totals.totalTime / (double) totalTime * 100;
+ // We don't print percentages < .01, so just drop those.
+ if (percentage >= 0.005 || totals.numPss != 0) {
+ if (prefix != null) {
+ pw.print(prefix);
+ }
+ if (label != null) {
+ pw.print(label);
+ }
+ totals.print(pw, totalTime, full);
+ if (prefix != null) {
+ pw.println();
+ }
+ }
+ }
+
+ public void dumpInternalLocked(PrintWriter pw, String prefix, boolean dumpAll) {
+ if (dumpAll) {
+ pw.print(prefix); pw.print("myID=");
+ pw.print(Integer.toHexString(System.identityHashCode(this)));
+ pw.print(" mCommonProcess=");
+ pw.print(Integer.toHexString(System.identityHashCode(mCommonProcess)));
+ pw.print(" mPackage="); pw.println(mPackage);
+ if (mMultiPackage) {
+ pw.print(prefix); pw.print("mMultiPackage="); pw.println(mMultiPackage);
+ }
+ if (this != mCommonProcess) {
+ pw.print(prefix); pw.print("Common Proc: "); pw.print(mCommonProcess.mName);
+ pw.print("/"); pw.print(mCommonProcess.mUid);
+ pw.print(" pkg="); pw.println(mCommonProcess.mPackage);
+ }
+ }
+ if (mActive) {
+ pw.print(prefix); pw.print("mActive="); pw.println(mActive);
+ }
+ if (mDead) {
+ pw.print(prefix); pw.print("mDead="); pw.println(mDead);
+ }
+ if (mNumActiveServices != 0 || mNumStartedServices != 0) {
+ pw.print(prefix); pw.print("mNumActiveServices="); pw.print(mNumActiveServices);
+ pw.print(" mNumStartedServices=");
+ pw.println(mNumStartedServices);
+ }
+ }
+
+ public void computeProcessData(ProcessStats.ProcessDataCollection data, long now) {
+ data.totalTime = 0;
+ data.numPss = data.minPss = data.avgPss = data.maxPss =
+ data.minUss = data.avgUss = data.maxUss = 0;
+ for (int is=0; is<data.screenStates.length; is++) {
+ for (int im=0; im<data.memStates.length; im++) {
+ for (int ip=0; ip<data.procStates.length; ip++) {
+ int bucket = ((data.screenStates[is] + data.memStates[im]) * STATE_COUNT)
+ + data.procStates[ip];
+ data.totalTime += getDuration(bucket, now);
+ long samples = getPssSampleCount(bucket);
+ if (samples > 0) {
+ long minPss = getPssMinimum(bucket);
+ long avgPss = getPssAverage(bucket);
+ long maxPss = getPssMaximum(bucket);
+ long minUss = getPssUssMinimum(bucket);
+ long avgUss = getPssUssAverage(bucket);
+ long maxUss = getPssUssMaximum(bucket);
+ if (data.numPss == 0) {
+ data.minPss = minPss;
+ data.avgPss = avgPss;
+ data.maxPss = maxPss;
+ data.minUss = minUss;
+ data.avgUss = avgUss;
+ data.maxUss = maxUss;
+ } else {
+ if (minPss < data.minPss) {
+ data.minPss = minPss;
+ }
+ data.avgPss = (long)( ((data.avgPss*(double)data.numPss)
+ + (avgPss*(double)samples)) / (data.numPss+samples) );
+ if (maxPss > data.maxPss) {
+ data.maxPss = maxPss;
+ }
+ if (minUss < data.minUss) {
+ data.minUss = minUss;
+ }
+ data.avgUss = (long)( ((data.avgUss*(double)data.numPss)
+ + (avgUss*(double)samples)) / (data.numPss+samples) );
+ if (maxUss > data.maxUss) {
+ data.maxUss = maxUss;
+ }
+ }
+ data.numPss += samples;
+ }
+ }
+ }
+ }
+ }
+
+ public void dumpCsv(PrintWriter pw,
+ boolean sepScreenStates, int[] screenStates, boolean sepMemStates,
+ int[] memStates, boolean sepProcStates, int[] procStates, long now) {
+ final int NSS = sepScreenStates ? screenStates.length : 1;
+ final int NMS = sepMemStates ? memStates.length : 1;
+ final int NPS = sepProcStates ? procStates.length : 1;
+ for (int iss=0; iss<NSS; iss++) {
+ for (int ims=0; ims<NMS; ims++) {
+ for (int ips=0; ips<NPS; ips++) {
+ final int vsscreen = sepScreenStates ? screenStates[iss] : 0;
+ final int vsmem = sepMemStates ? memStates[ims] : 0;
+ final int vsproc = sepProcStates ? procStates[ips] : 0;
+ final int NSA = sepScreenStates ? 1 : screenStates.length;
+ final int NMA = sepMemStates ? 1 : memStates.length;
+ final int NPA = sepProcStates ? 1 : procStates.length;
+ long totalTime = 0;
+ for (int isa=0; isa<NSA; isa++) {
+ for (int ima=0; ima<NMA; ima++) {
+ for (int ipa=0; ipa<NPA; ipa++) {
+ final int vascreen = sepScreenStates ? 0 : screenStates[isa];
+ final int vamem = sepMemStates ? 0 : memStates[ima];
+ final int vaproc = sepProcStates ? 0 : procStates[ipa];
+ final int bucket = ((vsscreen + vascreen + vsmem + vamem)
+ * STATE_COUNT) + vsproc + vaproc;
+ totalTime += getDuration(bucket, now);
+ }
+ }
+ }
+ pw.print(DumpUtils.CSV_SEP);
+ pw.print(totalTime);
+ }
+ }
+ }
+ }
+
+ public void dumpPackageProcCheckin(PrintWriter pw, String pkgName, int uid, int vers,
+ String itemName, long now) {
+ pw.print("pkgproc,");
+ pw.print(pkgName);
+ pw.print(",");
+ pw.print(uid);
+ pw.print(",");
+ pw.print(vers);
+ pw.print(",");
+ pw.print(DumpUtils.collapseString(pkgName, itemName));
+ dumpAllStateCheckin(pw, now);
+ pw.println();
+ if (mPssTable.getKeyCount() > 0) {
+ pw.print("pkgpss,");
+ pw.print(pkgName);
+ pw.print(",");
+ pw.print(uid);
+ pw.print(",");
+ pw.print(vers);
+ pw.print(",");
+ pw.print(DumpUtils.collapseString(pkgName, itemName));
+ dumpAllPssCheckin(pw);
+ pw.println();
+ }
+ if (mNumExcessiveWake > 0 || mNumExcessiveCpu > 0 || mNumCachedKill > 0) {
+ pw.print("pkgkills,");
+ pw.print(pkgName);
+ pw.print(",");
+ pw.print(uid);
+ pw.print(",");
+ pw.print(vers);
+ pw.print(",");
+ pw.print(DumpUtils.collapseString(pkgName, itemName));
+ pw.print(",");
+ pw.print(mNumExcessiveWake);
+ pw.print(",");
+ pw.print(mNumExcessiveCpu);
+ pw.print(",");
+ pw.print(mNumCachedKill);
+ pw.print(",");
+ pw.print(mMinCachedKillPss);
+ pw.print(":");
+ pw.print(mAvgCachedKillPss);
+ pw.print(":");
+ pw.print(mMaxCachedKillPss);
+ pw.println();
+ }
+ }
+
+ public void dumpProcCheckin(PrintWriter pw, String procName, int uid, long now) {
+ if (mDurations.getKeyCount() > 0) {
+ pw.print("proc,");
+ pw.print(procName);
+ pw.print(",");
+ pw.print(uid);
+ dumpAllStateCheckin(pw, now);
+ pw.println();
+ }
+ if (mPssTable.getKeyCount() > 0) {
+ pw.print("pss,");
+ pw.print(procName);
+ pw.print(",");
+ pw.print(uid);
+ dumpAllPssCheckin(pw);
+ pw.println();
+ }
+ if (mNumExcessiveWake > 0 || mNumExcessiveCpu > 0 || mNumCachedKill > 0) {
+ pw.print("kills,");
+ pw.print(procName);
+ pw.print(",");
+ pw.print(uid);
+ pw.print(",");
+ pw.print(mNumExcessiveWake);
+ pw.print(",");
+ pw.print(mNumExcessiveCpu);
+ pw.print(",");
+ pw.print(mNumCachedKill);
+ pw.print(",");
+ pw.print(mMinCachedKillPss);
+ pw.print(":");
+ pw.print(mAvgCachedKillPss);
+ pw.print(":");
+ pw.print(mMaxCachedKillPss);
+ pw.println();
+ }
+ }
+
+ public void dumpAllStateCheckin(PrintWriter pw, long now) {
+ boolean didCurState = false;
+ for (int i=0; i<mDurations.getKeyCount(); i++) {
+ final int key = mDurations.getKeyAt(i);
+ final int type = SparseMappingTable.getIdFromKey(key);
+ long time = mDurations.getValue(key);
+ if (mCurState == type) {
+ didCurState = true;
+ time += now - mStartTime;
+ }
+ DumpUtils.printProcStateTagAndValue(pw, type, time);
+ }
+ if (!didCurState && mCurState != STATE_NOTHING) {
+ DumpUtils.printProcStateTagAndValue(pw, mCurState, now - mStartTime);
+ }
+ }
+
+ public void dumpAllPssCheckin(PrintWriter pw) {
+ final int N = mPssTable.getKeyCount();
+ for (int i=0; i<N; i++) {
+ final int key = mPssTable.getKeyAt(i);
+ final int type = SparseMappingTable.getIdFromKey(key);
+ pw.print(',');
+ DumpUtils.printProcStateTag(pw, type);
+ pw.print(':');
+ pw.print(mPssTable.getValue(key, PSS_SAMPLE_COUNT));
+ pw.print(':');
+ pw.print(mPssTable.getValue(key, PSS_MINIMUM));
+ pw.print(':');
+ pw.print(mPssTable.getValue(key, PSS_AVERAGE));
+ pw.print(':');
+ pw.print(mPssTable.getValue(key, PSS_MAXIMUM));
+ pw.print(':');
+ pw.print(mPssTable.getValue(key, PSS_USS_MINIMUM));
+ pw.print(':');
+ pw.print(mPssTable.getValue(key, PSS_USS_AVERAGE));
+ pw.print(':');
+ pw.print(mPssTable.getValue(key, PSS_USS_MAXIMUM));
+ }
+ }
+
+ public String toString() {
+ StringBuilder sb = new StringBuilder(128);
+ sb.append("ProcessState{").append(Integer.toHexString(System.identityHashCode(this)))
+ .append(" ").append(mName).append("/").append(mUid)
+ .append(" pkg=").append(mPackage);
+ if (mMultiPackage) sb.append(" (multi)");
+ if (mCommonProcess != this) sb.append(" (sub)");
+ sb.append("}");
+ return sb.toString();
+ }
+}
diff --git a/core/java/com/android/internal/app/ProcessStats.aidl b/core/java/com/android/internal/app/procstats/ProcessStats.aidl
similarity index 93%
rename from core/java/com/android/internal/app/ProcessStats.aidl
rename to core/java/com/android/internal/app/procstats/ProcessStats.aidl
index 48b1f85..33639a0 100644
--- a/core/java/com/android/internal/app/ProcessStats.aidl
+++ b/core/java/com/android/internal/app/procstats/ProcessStats.aidl
@@ -14,6 +14,6 @@
** limitations under the License.
*/
-package com.android.internal.app;
+package com.android.internal.app.procstats;
parcelable ProcessStats;
diff --git a/core/java/com/android/internal/app/procstats/ProcessStats.java b/core/java/com/android/internal/app/procstats/ProcessStats.java
new file mode 100644
index 0000000..06542f7
--- /dev/null
+++ b/core/java/com/android/internal/app/procstats/ProcessStats.java
@@ -0,0 +1,1621 @@
+/*
+ * Copyright (C) 2013 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.app.procstats;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.SystemClock;
+import android.os.SystemProperties;
+import android.os.UserHandle;
+import android.text.format.DateFormat;
+import android.util.ArrayMap;
+import android.util.ArraySet;
+import android.util.DebugUtils;
+import android.util.Log;
+import android.util.Slog;
+import android.util.SparseArray;
+import android.util.TimeUtils;
+
+import com.android.internal.app.ProcessMap;
+import com.android.internal.app.procstats.DurationsTable;
+import com.android.internal.app.procstats.ProcessState;
+import com.android.internal.app.procstats.PssTable;
+import com.android.internal.app.procstats.ServiceState;
+import com.android.internal.app.procstats.SparseMappingTable;
+import com.android.internal.app.procstats.SysMemUsageTable;
+import com.android.internal.app.procstats.DumpUtils.*;
+
+import dalvik.system.VMRuntime;
+import libcore.util.EmptyArray;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Objects;
+
+public final class ProcessStats implements Parcelable {
+ public static final String TAG = "ProcessStats";
+ static final boolean DEBUG = false;
+ static final boolean DEBUG_PARCEL = false;
+
+ public static final String SERVICE_NAME = "procstats";
+
+ // How often the service commits its data, giving the minimum batching
+ // that is done.
+ public static long COMMIT_PERIOD = 3*60*60*1000; // Commit current stats every 3 hours
+
+ // Minimum uptime period before committing. If the COMMIT_PERIOD has elapsed but
+ // the total uptime has not exceeded this amount, then the commit will be held until
+ // it is reached.
+ public static long COMMIT_UPTIME_PERIOD = 60*60*1000; // Must have at least 1 hour elapsed
+
+ public static final int STATE_NOTHING = -1;
+ public static final int STATE_PERSISTENT = 0;
+ public static final int STATE_TOP = 1;
+ public static final int STATE_IMPORTANT_FOREGROUND = 2;
+ public static final int STATE_IMPORTANT_BACKGROUND = 3;
+ public static final int STATE_BACKUP = 4;
+ public static final int STATE_HEAVY_WEIGHT = 5;
+ public static final int STATE_SERVICE = 6;
+ public static final int STATE_SERVICE_RESTARTING = 7;
+ public static final int STATE_RECEIVER = 8;
+ public static final int STATE_HOME = 9;
+ public static final int STATE_LAST_ACTIVITY = 10;
+ public static final int STATE_CACHED_ACTIVITY = 11;
+ public static final int STATE_CACHED_ACTIVITY_CLIENT = 12;
+ public static final int STATE_CACHED_EMPTY = 13;
+ public static final int STATE_COUNT = STATE_CACHED_EMPTY+1;
+
+ public static final int PSS_SAMPLE_COUNT = 0;
+ public static final int PSS_MINIMUM = 1;
+ public static final int PSS_AVERAGE = 2;
+ public static final int PSS_MAXIMUM = 3;
+ public static final int PSS_USS_MINIMUM = 4;
+ public static final int PSS_USS_AVERAGE = 5;
+ public static final int PSS_USS_MAXIMUM = 6;
+ public static final int PSS_COUNT = PSS_USS_MAXIMUM+1;
+
+ public static final int SYS_MEM_USAGE_SAMPLE_COUNT = 0;
+ public static final int SYS_MEM_USAGE_CACHED_MINIMUM = 1;
+ public static final int SYS_MEM_USAGE_CACHED_AVERAGE = 2;
+ public static final int SYS_MEM_USAGE_CACHED_MAXIMUM = 3;
+ public static final int SYS_MEM_USAGE_FREE_MINIMUM = 4;
+ public static final int SYS_MEM_USAGE_FREE_AVERAGE = 5;
+ public static final int SYS_MEM_USAGE_FREE_MAXIMUM = 6;
+ public static final int SYS_MEM_USAGE_ZRAM_MINIMUM = 7;
+ public static final int SYS_MEM_USAGE_ZRAM_AVERAGE = 8;
+ public static final int SYS_MEM_USAGE_ZRAM_MAXIMUM = 9;
+ public static final int SYS_MEM_USAGE_KERNEL_MINIMUM = 10;
+ public static final int SYS_MEM_USAGE_KERNEL_AVERAGE = 11;
+ public static final int SYS_MEM_USAGE_KERNEL_MAXIMUM = 12;
+ public static final int SYS_MEM_USAGE_NATIVE_MINIMUM = 13;
+ public static final int SYS_MEM_USAGE_NATIVE_AVERAGE = 14;
+ public static final int SYS_MEM_USAGE_NATIVE_MAXIMUM = 15;
+ public static final int SYS_MEM_USAGE_COUNT = SYS_MEM_USAGE_NATIVE_MAXIMUM+1;
+
+ public static final int ADJ_NOTHING = -1;
+ public static final int ADJ_MEM_FACTOR_NORMAL = 0;
+ public static final int ADJ_MEM_FACTOR_MODERATE = 1;
+ public static final int ADJ_MEM_FACTOR_LOW = 2;
+ public static final int ADJ_MEM_FACTOR_CRITICAL = 3;
+ public static final int ADJ_MEM_FACTOR_COUNT = ADJ_MEM_FACTOR_CRITICAL+1;
+ public static final int ADJ_SCREEN_MOD = ADJ_MEM_FACTOR_COUNT;
+ public static final int ADJ_SCREEN_OFF = 0;
+ public static final int ADJ_SCREEN_ON = ADJ_SCREEN_MOD;
+ public static final int ADJ_COUNT = ADJ_SCREEN_ON*2;
+
+ public static final int FLAG_COMPLETE = 1<<0;
+ public static final int FLAG_SHUTDOWN = 1<<1;
+ public static final int FLAG_SYSPROPS = 1<<2;
+
+ public static final int[] ALL_MEM_ADJ = new int[] { ADJ_MEM_FACTOR_NORMAL,
+ ADJ_MEM_FACTOR_MODERATE, ADJ_MEM_FACTOR_LOW, ADJ_MEM_FACTOR_CRITICAL };
+
+ public static final int[] ALL_SCREEN_ADJ = new int[] { ADJ_SCREEN_OFF, ADJ_SCREEN_ON };
+
+ public static final int[] NON_CACHED_PROC_STATES = new int[] {
+ STATE_PERSISTENT, STATE_TOP, STATE_IMPORTANT_FOREGROUND,
+ STATE_IMPORTANT_BACKGROUND, STATE_BACKUP, STATE_HEAVY_WEIGHT,
+ STATE_SERVICE, STATE_SERVICE_RESTARTING, STATE_RECEIVER
+ };
+
+ public static final int[] BACKGROUND_PROC_STATES = new int[] {
+ STATE_IMPORTANT_FOREGROUND, STATE_IMPORTANT_BACKGROUND, STATE_BACKUP,
+ STATE_HEAVY_WEIGHT, STATE_SERVICE, STATE_SERVICE_RESTARTING, STATE_RECEIVER
+ };
+
+ public static final int[] ALL_PROC_STATES = new int[] { STATE_PERSISTENT,
+ STATE_TOP, STATE_IMPORTANT_FOREGROUND, STATE_IMPORTANT_BACKGROUND, STATE_BACKUP,
+ STATE_HEAVY_WEIGHT, STATE_SERVICE, STATE_SERVICE_RESTARTING, STATE_RECEIVER,
+ STATE_HOME, STATE_LAST_ACTIVITY, STATE_CACHED_ACTIVITY,
+ STATE_CACHED_ACTIVITY_CLIENT, STATE_CACHED_EMPTY
+ };
+
+ // Current version of the parcel format.
+ private static final int PARCEL_VERSION = 19;
+ // In-memory Parcel magic number, used to detect attempts to unmarshall bad data
+ private static final int MAGIC = 0x50535454;
+
+ public String mReadError;
+ public String mTimePeriodStartClockStr;
+ public int mFlags;
+
+ public final ProcessMap<SparseArray<PackageState>> mPackages
+ = new ProcessMap<SparseArray<PackageState>>();
+ public final ProcessMap<ProcessState> mProcesses = new ProcessMap<ProcessState>();
+
+ public final long[] mMemFactorDurations = new long[ADJ_COUNT];
+ public int mMemFactor = STATE_NOTHING;
+ public long mStartTime;
+
+ public long mTimePeriodStartClock;
+ public long mTimePeriodStartRealtime;
+ public long mTimePeriodEndRealtime;
+ public long mTimePeriodStartUptime;
+ public long mTimePeriodEndUptime;
+ String mRuntime;
+ boolean mRunning;
+
+ public final SparseMappingTable mTableData = new SparseMappingTable();
+
+ int[] mAddLongTable;
+ int mAddLongTableSize;
+
+ public final long[] mSysMemUsageArgs = new long[SYS_MEM_USAGE_COUNT];
+ public final SysMemUsageTable mSysMemUsage = new SysMemUsageTable(mTableData);
+
+ // For writing parcels.
+ ArrayMap<String, Integer> mCommonStringToIndex;
+
+ // For reading parcels.
+ ArrayList<String> mIndexToCommonString;
+
+ public ProcessStats(boolean running) {
+ mRunning = running;
+ reset();
+ }
+
+ public ProcessStats(Parcel in) {
+ reset();
+ readFromParcel(in);
+ }
+
+ public void add(ProcessStats other) {
+ ArrayMap<String, SparseArray<SparseArray<PackageState>>> pkgMap = other.mPackages.getMap();
+ for (int ip=0; ip<pkgMap.size(); ip++) {
+ final String pkgName = pkgMap.keyAt(ip);
+ final SparseArray<SparseArray<PackageState>> uids = pkgMap.valueAt(ip);
+ for (int iu=0; iu<uids.size(); iu++) {
+ final int uid = uids.keyAt(iu);
+ final SparseArray<PackageState> versions = uids.valueAt(iu);
+ for (int iv=0; iv<versions.size(); iv++) {
+ final int vers = versions.keyAt(iv);
+ final PackageState otherState = versions.valueAt(iv);
+ final int NPROCS = otherState.mProcesses.size();
+ final int NSRVS = otherState.mServices.size();
+ for (int iproc=0; iproc<NPROCS; iproc++) {
+ ProcessState otherProc = otherState.mProcesses.valueAt(iproc);
+ if (otherProc.getCommonProcess() != otherProc) {
+ if (DEBUG) Slog.d(TAG, "Adding pkg " + pkgName + " uid " + uid
+ + " vers " + vers + " proc " + otherProc.getName());
+ ProcessState thisProc = getProcessStateLocked(pkgName, uid, vers,
+ otherProc.getName());
+ if (thisProc.getCommonProcess() == thisProc) {
+ if (DEBUG) Slog.d(TAG, "Existing process is single-package, splitting");
+ thisProc.setMultiPackage(true);
+ long now = SystemClock.uptimeMillis();
+ final PackageState pkgState = getPackageStateLocked(pkgName, uid,
+ vers);
+ thisProc = thisProc.clone(now);
+ pkgState.mProcesses.put(thisProc.getName(), thisProc);
+ }
+ thisProc.add(otherProc);
+ }
+ }
+ for (int isvc=0; isvc<NSRVS; isvc++) {
+ ServiceState otherSvc = otherState.mServices.valueAt(isvc);
+ if (DEBUG) Slog.d(TAG, "Adding pkg " + pkgName + " uid " + uid
+ + " service " + otherSvc.getName());
+ ServiceState thisSvc = getServiceStateLocked(pkgName, uid, vers,
+ otherSvc.getProcessName(), otherSvc.getName());
+ thisSvc.add(otherSvc);
+ }
+ }
+ }
+ }
+
+ ArrayMap<String, SparseArray<ProcessState>> procMap = other.mProcesses.getMap();
+ for (int ip=0; ip<procMap.size(); ip++) {
+ SparseArray<ProcessState> uids = procMap.valueAt(ip);
+ for (int iu=0; iu<uids.size(); iu++) {
+ int uid = uids.keyAt(iu);
+ ProcessState otherProc = uids.valueAt(iu);
+ final String name = otherProc.getName();
+ final String pkg = otherProc.getPackage();
+ final int vers = otherProc.getVersion();
+ ProcessState thisProc = mProcesses.get(name, uid);
+ if (DEBUG) Slog.d(TAG, "Adding uid " + uid + " proc " + name);
+ if (thisProc == null) {
+ if (DEBUG) Slog.d(TAG, "Creating new process!");
+ thisProc = new ProcessState(this, pkg, uid, vers, name);
+ mProcesses.put(name, uid, thisProc);
+ PackageState thisState = getPackageStateLocked(pkg, uid, vers);
+ if (!thisState.mProcesses.containsKey(name)) {
+ thisState.mProcesses.put(name, thisProc);
+ }
+ }
+ thisProc.add(otherProc);
+ }
+ }
+
+ for (int i=0; i<ADJ_COUNT; i++) {
+ if (DEBUG) Slog.d(TAG, "Total duration #" + i + " inc by "
+ + other.mMemFactorDurations[i] + " from "
+ + mMemFactorDurations[i]);
+ mMemFactorDurations[i] += other.mMemFactorDurations[i];
+ }
+
+ mSysMemUsage.mergeStats(other.mSysMemUsage);
+
+ if (other.mTimePeriodStartClock < mTimePeriodStartClock) {
+ mTimePeriodStartClock = other.mTimePeriodStartClock;
+ mTimePeriodStartClockStr = other.mTimePeriodStartClockStr;
+ }
+ mTimePeriodEndRealtime += other.mTimePeriodEndRealtime - other.mTimePeriodStartRealtime;
+ mTimePeriodEndUptime += other.mTimePeriodEndUptime - other.mTimePeriodStartUptime;
+ }
+
+ public void addSysMemUsage(long cachedMem, long freeMem, long zramMem, long kernelMem,
+ long nativeMem) {
+ if (mMemFactor != STATE_NOTHING) {
+ int state = mMemFactor * STATE_COUNT;
+ mSysMemUsageArgs[SYS_MEM_USAGE_SAMPLE_COUNT] = 1;
+ for (int i=0; i<3; i++) {
+ mSysMemUsageArgs[SYS_MEM_USAGE_CACHED_MINIMUM + i] = cachedMem;
+ mSysMemUsageArgs[SYS_MEM_USAGE_FREE_MINIMUM + i] = freeMem;
+ mSysMemUsageArgs[SYS_MEM_USAGE_ZRAM_MINIMUM + i] = zramMem;
+ mSysMemUsageArgs[SYS_MEM_USAGE_KERNEL_MINIMUM + i] = kernelMem;
+ mSysMemUsageArgs[SYS_MEM_USAGE_NATIVE_MINIMUM + i] = nativeMem;
+ }
+ mSysMemUsage.mergeStats(state, mSysMemUsageArgs, 0);
+ }
+ }
+
+ public static final Parcelable.Creator<ProcessStats> CREATOR
+ = new Parcelable.Creator<ProcessStats>() {
+ public ProcessStats createFromParcel(Parcel in) {
+ return new ProcessStats(in);
+ }
+
+ public ProcessStats[] newArray(int size) {
+ return new ProcessStats[size];
+ }
+ };
+
+ public void computeTotalMemoryUse(TotalMemoryUseCollection data, long now) {
+ data.totalTime = 0;
+ for (int i=0; i<STATE_COUNT; i++) {
+ data.processStateWeight[i] = 0;
+ data.processStatePss[i] = 0;
+ data.processStateTime[i] = 0;
+ data.processStateSamples[i] = 0;
+ }
+ for (int i=0; i<SYS_MEM_USAGE_COUNT; i++) {
+ data.sysMemUsage[i] = 0;
+ }
+ data.sysMemCachedWeight = 0;
+ data.sysMemFreeWeight = 0;
+ data.sysMemZRamWeight = 0;
+ data.sysMemKernelWeight = 0;
+ data.sysMemNativeWeight = 0;
+ data.sysMemSamples = 0;
+ final long[] totalMemUsage = mSysMemUsage.getTotalMemUsage();
+ for (int is=0; is<data.screenStates.length; is++) {
+ for (int im=0; im<data.memStates.length; im++) {
+ int memBucket = data.screenStates[is] + data.memStates[im];
+ int stateBucket = memBucket * STATE_COUNT;
+ long memTime = mMemFactorDurations[memBucket];
+ if (mMemFactor == memBucket) {
+ memTime += now - mStartTime;
+ }
+ data.totalTime += memTime;
+ final int sysKey = mSysMemUsage.getKey((byte)stateBucket);
+ long[] longs = totalMemUsage;
+ int idx = 0;
+ if (sysKey != SparseMappingTable.INVALID_KEY) {
+ final long[] tmpLongs = mSysMemUsage.getArrayForKey(sysKey);
+ final int tmpIndex = SparseMappingTable.getIndexFromKey(sysKey);
+ if (tmpLongs[tmpIndex+SYS_MEM_USAGE_SAMPLE_COUNT] >= 3) {
+ SysMemUsageTable.mergeSysMemUsage(data.sysMemUsage, 0, longs, idx);
+ longs = tmpLongs;
+ idx = tmpIndex;
+ }
+ }
+ data.sysMemCachedWeight += longs[idx+SYS_MEM_USAGE_CACHED_AVERAGE]
+ * (double)memTime;
+ data.sysMemFreeWeight += longs[idx+SYS_MEM_USAGE_FREE_AVERAGE]
+ * (double)memTime;
+ data.sysMemZRamWeight += longs[idx+SYS_MEM_USAGE_ZRAM_AVERAGE]
+ * (double)memTime;
+ data.sysMemKernelWeight += longs[idx+SYS_MEM_USAGE_KERNEL_AVERAGE]
+ * (double)memTime;
+ data.sysMemNativeWeight += longs[idx+SYS_MEM_USAGE_NATIVE_AVERAGE]
+ * (double)memTime;
+ data.sysMemSamples += longs[idx+SYS_MEM_USAGE_SAMPLE_COUNT];
+ }
+ }
+ ArrayMap<String, SparseArray<ProcessState>> procMap = mProcesses.getMap();
+ for (int iproc=0; iproc<procMap.size(); iproc++) {
+ SparseArray<ProcessState> uids = procMap.valueAt(iproc);
+ for (int iu=0; iu<uids.size(); iu++) {
+ final ProcessState proc = uids.valueAt(iu);
+ proc.aggregatePss(data, now);
+ }
+ }
+ }
+
+ public void reset() {
+ if (DEBUG) Slog.d(TAG, "Resetting state of " + mTimePeriodStartClockStr);
+ resetCommon();
+ mPackages.getMap().clear();
+ mProcesses.getMap().clear();
+ mMemFactor = STATE_NOTHING;
+ mStartTime = 0;
+ if (DEBUG) Slog.d(TAG, "State reset; now " + mTimePeriodStartClockStr);
+ }
+
+ public void resetSafely() {
+ if (DEBUG) Slog.d(TAG, "Safely resetting state of " + mTimePeriodStartClockStr);
+ resetCommon();
+
+ // First initialize use count of all common processes.
+ final long now = SystemClock.uptimeMillis();
+ final ArrayMap<String, SparseArray<ProcessState>> procMap = mProcesses.getMap();
+ for (int ip=procMap.size()-1; ip>=0; ip--) {
+ final SparseArray<ProcessState> uids = procMap.valueAt(ip);
+ for (int iu=uids.size()-1; iu>=0; iu--) {
+ uids.valueAt(iu).tmpNumInUse = 0;
+ }
+ }
+
+ // Next reset or prune all per-package processes, and for the ones that are reset
+ // track this back to the common processes.
+ final ArrayMap<String, SparseArray<SparseArray<PackageState>>> pkgMap = mPackages.getMap();
+ for (int ip=pkgMap.size()-1; ip>=0; ip--) {
+ final SparseArray<SparseArray<PackageState>> uids = pkgMap.valueAt(ip);
+ for (int iu=uids.size()-1; iu>=0; iu--) {
+ final SparseArray<PackageState> vpkgs = uids.valueAt(iu);
+ for (int iv=vpkgs.size()-1; iv>=0; iv--) {
+ final PackageState pkgState = vpkgs.valueAt(iv);
+ for (int iproc=pkgState.mProcesses.size()-1; iproc>=0; iproc--) {
+ final ProcessState ps = pkgState.mProcesses.valueAt(iproc);
+ if (ps.isInUse()) {
+ ps.resetSafely(now);
+ ps.getCommonProcess().tmpNumInUse++;
+ ps.getCommonProcess().tmpFoundSubProc = ps;
+ } else {
+ pkgState.mProcesses.valueAt(iproc).makeDead();
+ pkgState.mProcesses.removeAt(iproc);
+ }
+ }
+ for (int isvc=pkgState.mServices.size()-1; isvc>=0; isvc--) {
+ final ServiceState ss = pkgState.mServices.valueAt(isvc);
+ if (ss.isInUse()) {
+ ss.resetSafely(now);
+ } else {
+ pkgState.mServices.removeAt(isvc);
+ }
+ }
+ if (pkgState.mProcesses.size() <= 0 && pkgState.mServices.size() <= 0) {
+ vpkgs.removeAt(iv);
+ }
+ }
+ if (vpkgs.size() <= 0) {
+ uids.removeAt(iu);
+ }
+ }
+ if (uids.size() <= 0) {
+ pkgMap.removeAt(ip);
+ }
+ }
+
+ // Finally prune out any common processes that are no longer in use.
+ for (int ip=procMap.size()-1; ip>=0; ip--) {
+ final SparseArray<ProcessState> uids = procMap.valueAt(ip);
+ for (int iu=uids.size()-1; iu>=0; iu--) {
+ ProcessState ps = uids.valueAt(iu);
+ if (ps.isInUse() || ps.tmpNumInUse > 0) {
+ // If this is a process for multiple packages, we could at this point
+ // be back down to one package. In that case, we want to revert back
+ // to a single shared ProcessState. We can do this by converting the
+ // current package-specific ProcessState up to the shared ProcessState,
+ // throwing away the current one we have here (because nobody else is
+ // using it).
+ if (!ps.isActive() && ps.isMultiPackage() && ps.tmpNumInUse == 1) {
+ // Here we go...
+ ps = ps.tmpFoundSubProc;
+ ps.makeStandalone();
+ uids.setValueAt(iu, ps);
+ } else {
+ ps.resetSafely(now);
+ }
+ } else {
+ ps.makeDead();
+ uids.removeAt(iu);
+ }
+ }
+ if (uids.size() <= 0) {
+ procMap.removeAt(ip);
+ }
+ }
+
+ mStartTime = now;
+ if (DEBUG) Slog.d(TAG, "State reset; now " + mTimePeriodStartClockStr);
+ }
+
+ private void resetCommon() {
+ mTimePeriodStartClock = System.currentTimeMillis();
+ buildTimePeriodStartClockStr();
+ mTimePeriodStartRealtime = mTimePeriodEndRealtime = SystemClock.elapsedRealtime();
+ mTimePeriodStartUptime = mTimePeriodEndUptime = SystemClock.uptimeMillis();
+ mTableData.reset();
+ Arrays.fill(mMemFactorDurations, 0);
+ mSysMemUsage.resetTable();
+ mStartTime = 0;
+ mReadError = null;
+ mFlags = 0;
+ evaluateSystemProperties(true);
+ }
+
+ public boolean evaluateSystemProperties(boolean update) {
+ boolean changed = false;
+ String runtime = SystemProperties.get("persist.sys.dalvik.vm.lib.2",
+ VMRuntime.getRuntime().vmLibrary());
+ if (!Objects.equals(runtime, mRuntime)) {
+ changed = true;
+ if (update) {
+ mRuntime = runtime;
+ }
+ }
+ return changed;
+ }
+
+ private void buildTimePeriodStartClockStr() {
+ mTimePeriodStartClockStr = DateFormat.format("yyyy-MM-dd-HH-mm-ss",
+ mTimePeriodStartClock).toString();
+ }
+
+ static final int[] BAD_TABLE = new int[0];
+
+ private void writeCompactedLongArray(Parcel out, long[] array, int num) {
+ for (int i=0; i<num; i++) {
+ long val = array[i];
+ if (val < 0) {
+ Slog.w(TAG, "Time val negative: " + val);
+ val = 0;
+ }
+ if (val <= Integer.MAX_VALUE) {
+ out.writeInt((int)val);
+ } else {
+ int top = ~((int)((val>>32)&0x7fffffff));
+ int bottom = (int)(val&0xfffffff);
+ out.writeInt(top);
+ out.writeInt(bottom);
+ }
+ }
+ }
+
+ private void readCompactedLongArray(Parcel in, int version, long[] array, int num) {
+ if (version <= 10) {
+ in.readLongArray(array);
+ return;
+ }
+ final int alen = array.length;
+ if (num > alen) {
+ throw new RuntimeException("bad array lengths: got " + num + " array is " + alen);
+ }
+ int i;
+ for (i=0; i<num; i++) {
+ int val = in.readInt();
+ if (val >= 0) {
+ array[i] = val;
+ } else {
+ int bottom = in.readInt();
+ array[i] = (((long)~val)<<32) | bottom;
+ }
+ }
+ while (i < alen) {
+ array[i] = 0;
+ i++;
+ }
+ }
+
+ private void writeCommonString(Parcel out, String name) {
+ Integer index = mCommonStringToIndex.get(name);
+ if (index != null) {
+ out.writeInt(index);
+ return;
+ }
+ index = mCommonStringToIndex.size();
+ mCommonStringToIndex.put(name, index);
+ out.writeInt(~index);
+ out.writeString(name);
+ }
+
+ private String readCommonString(Parcel in, int version) {
+ if (version <= 9) {
+ return in.readString();
+ }
+ int index = in.readInt();
+ if (index >= 0) {
+ return mIndexToCommonString.get(index);
+ }
+ index = ~index;
+ String name = in.readString();
+ while (mIndexToCommonString.size() <= index) {
+ mIndexToCommonString.add(null);
+ }
+ mIndexToCommonString.set(index, name);
+ return name;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel out, int flags) {
+ writeToParcel(out, SystemClock.uptimeMillis(), flags);
+ }
+
+ /** @hide */
+ public void writeToParcel(Parcel out, long now, int flags) {
+ out.writeInt(MAGIC);
+ out.writeInt(PARCEL_VERSION);
+ out.writeInt(STATE_COUNT);
+ out.writeInt(ADJ_COUNT);
+ out.writeInt(PSS_COUNT);
+ out.writeInt(SYS_MEM_USAGE_COUNT);
+ out.writeInt(SparseMappingTable.ARRAY_SIZE);
+
+ mCommonStringToIndex = new ArrayMap<String, Integer>(mProcesses.size());
+
+ // First commit all running times.
+ ArrayMap<String, SparseArray<ProcessState>> procMap = mProcesses.getMap();
+ final int NPROC = procMap.size();
+ for (int ip=0; ip<NPROC; ip++) {
+ SparseArray<ProcessState> uids = procMap.valueAt(ip);
+ final int NUID = uids.size();
+ for (int iu=0; iu<NUID; iu++) {
+ uids.valueAt(iu).commitStateTime(now);
+ }
+ }
+ final ArrayMap<String, SparseArray<SparseArray<PackageState>>> pkgMap = mPackages.getMap();
+ final int NPKG = pkgMap.size();
+ for (int ip=0; ip<NPKG; ip++) {
+ final SparseArray<SparseArray<PackageState>> uids = pkgMap.valueAt(ip);
+ final int NUID = uids.size();
+ for (int iu=0; iu<NUID; iu++) {
+ final SparseArray<PackageState> vpkgs = uids.valueAt(iu);
+ final int NVERS = vpkgs.size();
+ for (int iv=0; iv<NVERS; iv++) {
+ PackageState pkgState = vpkgs.valueAt(iv);
+ final int NPROCS = pkgState.mProcesses.size();
+ for (int iproc=0; iproc<NPROCS; iproc++) {
+ ProcessState proc = pkgState.mProcesses.valueAt(iproc);
+ if (proc.getCommonProcess() != proc) {
+ proc.commitStateTime(now);
+ }
+ }
+ final int NSRVS = pkgState.mServices.size();
+ for (int isvc=0; isvc<NSRVS; isvc++) {
+ pkgState.mServices.valueAt(isvc).commitStateTime(now);
+ }
+ }
+ }
+ }
+
+ out.writeLong(mTimePeriodStartClock);
+ out.writeLong(mTimePeriodStartRealtime);
+ out.writeLong(mTimePeriodEndRealtime);
+ out.writeLong(mTimePeriodStartUptime);
+ out.writeLong(mTimePeriodEndUptime);
+ out.writeString(mRuntime);
+ out.writeInt(mFlags);
+
+ mTableData.writeToParcel(out);
+
+ if (mMemFactor != STATE_NOTHING) {
+ mMemFactorDurations[mMemFactor] += now - mStartTime;
+ mStartTime = now;
+ }
+ writeCompactedLongArray(out, mMemFactorDurations, mMemFactorDurations.length);
+
+ mSysMemUsage.writeToParcel(out);
+
+ out.writeInt(NPROC);
+ for (int ip=0; ip<NPROC; ip++) {
+ writeCommonString(out, procMap.keyAt(ip));
+ final SparseArray<ProcessState> uids = procMap.valueAt(ip);
+ final int NUID = uids.size();
+ out.writeInt(NUID);
+ for (int iu=0; iu<NUID; iu++) {
+ out.writeInt(uids.keyAt(iu));
+ final ProcessState proc = uids.valueAt(iu);
+ writeCommonString(out, proc.getPackage());
+ out.writeInt(proc.getVersion());
+ proc.writeToParcel(out, now);
+ }
+ }
+ out.writeInt(NPKG);
+ for (int ip=0; ip<NPKG; ip++) {
+ writeCommonString(out, pkgMap.keyAt(ip));
+ final SparseArray<SparseArray<PackageState>> uids = pkgMap.valueAt(ip);
+ final int NUID = uids.size();
+ out.writeInt(NUID);
+ for (int iu=0; iu<NUID; iu++) {
+ out.writeInt(uids.keyAt(iu));
+ final SparseArray<PackageState> vpkgs = uids.valueAt(iu);
+ final int NVERS = vpkgs.size();
+ out.writeInt(NVERS);
+ for (int iv=0; iv<NVERS; iv++) {
+ out.writeInt(vpkgs.keyAt(iv));
+ final PackageState pkgState = vpkgs.valueAt(iv);
+ final int NPROCS = pkgState.mProcesses.size();
+ out.writeInt(NPROCS);
+ for (int iproc=0; iproc<NPROCS; iproc++) {
+ writeCommonString(out, pkgState.mProcesses.keyAt(iproc));
+ final ProcessState proc = pkgState.mProcesses.valueAt(iproc);
+ if (proc.getCommonProcess() == proc) {
+ // This is the same as the common process we wrote above.
+ out.writeInt(0);
+ } else {
+ // There is separate data for this package's process.
+ out.writeInt(1);
+ proc.writeToParcel(out, now);
+ }
+ }
+ final int NSRVS = pkgState.mServices.size();
+ out.writeInt(NSRVS);
+ for (int isvc=0; isvc<NSRVS; isvc++) {
+ out.writeString(pkgState.mServices.keyAt(isvc));
+ final ServiceState svc = pkgState.mServices.valueAt(isvc);
+ writeCommonString(out, svc.getProcessName());
+ svc.writeToParcel(out, now);
+ }
+ }
+ }
+ }
+
+ mCommonStringToIndex = null;
+ }
+
+ private boolean readCheckedInt(Parcel in, int val, String what) {
+ int got;
+ if ((got=in.readInt()) != val) {
+ mReadError = "bad " + what + ": " + got;
+ return false;
+ }
+ return true;
+ }
+
+ static byte[] readFully(InputStream stream, int[] outLen) throws IOException {
+ int pos = 0;
+ final int initialAvail = stream.available();
+ byte[] data = new byte[initialAvail > 0 ? (initialAvail+1) : 16384];
+ while (true) {
+ int amt = stream.read(data, pos, data.length-pos);
+ if (DEBUG_PARCEL) Slog.i("foo", "Read " + amt + " bytes at " + pos
+ + " of avail " + data.length);
+ if (amt < 0) {
+ if (DEBUG_PARCEL) Slog.i("foo", "**** FINISHED READING: pos=" + pos
+ + " len=" + data.length);
+ outLen[0] = pos;
+ return data;
+ }
+ pos += amt;
+ if (pos >= data.length) {
+ byte[] newData = new byte[pos+16384];
+ if (DEBUG_PARCEL) Slog.i(TAG, "Copying " + pos + " bytes to new array len "
+ + newData.length);
+ System.arraycopy(data, 0, newData, 0, pos);
+ data = newData;
+ }
+ }
+ }
+
+ public void read(InputStream stream) {
+ try {
+ int[] len = new int[1];
+ byte[] raw = readFully(stream, len);
+ Parcel in = Parcel.obtain();
+ in.unmarshall(raw, 0, len[0]);
+ in.setDataPosition(0);
+ stream.close();
+
+ readFromParcel(in);
+ } catch (IOException e) {
+ mReadError = "caught exception: " + e;
+ }
+ }
+
+ public void readFromParcel(Parcel in) {
+ final boolean hadData = mPackages.getMap().size() > 0
+ || mProcesses.getMap().size() > 0;
+ if (hadData) {
+ resetSafely();
+ }
+
+ if (!readCheckedInt(in, MAGIC, "magic number")) {
+ return;
+ }
+ int version = in.readInt();
+ if (version != PARCEL_VERSION) {
+ mReadError = "bad version: " + version;
+ return;
+ }
+ if (!readCheckedInt(in, STATE_COUNT, "state count")) {
+ return;
+ }
+ if (!readCheckedInt(in, ADJ_COUNT, "adj count")) {
+ return;
+ }
+ if (!readCheckedInt(in, PSS_COUNT, "pss count")) {
+ return;
+ }
+ if (!readCheckedInt(in, SYS_MEM_USAGE_COUNT, "sys mem usage count")) {
+ return;
+ }
+ if (!readCheckedInt(in, SparseMappingTable.ARRAY_SIZE, "longs size")) {
+ return;
+ }
+
+ mIndexToCommonString = new ArrayList<String>();
+
+ mTimePeriodStartClock = in.readLong();
+ buildTimePeriodStartClockStr();
+ mTimePeriodStartRealtime = in.readLong();
+ mTimePeriodEndRealtime = in.readLong();
+ mTimePeriodStartUptime = in.readLong();
+ mTimePeriodEndUptime = in.readLong();
+ mRuntime = in.readString();
+ mFlags = in.readInt();
+ mTableData.readFromParcel(in);
+ readCompactedLongArray(in, version, mMemFactorDurations, mMemFactorDurations.length);
+ if (!mSysMemUsage.readFromParcel(in)) {
+ return;
+ }
+
+ int NPROC = in.readInt();
+ if (NPROC < 0) {
+ mReadError = "bad process count: " + NPROC;
+ return;
+ }
+ while (NPROC > 0) {
+ NPROC--;
+ final String procName = readCommonString(in, version);
+ if (procName == null) {
+ mReadError = "bad process name";
+ return;
+ }
+ int NUID = in.readInt();
+ if (NUID < 0) {
+ mReadError = "bad uid count: " + NUID;
+ return;
+ }
+ while (NUID > 0) {
+ NUID--;
+ final int uid = in.readInt();
+ if (uid < 0) {
+ mReadError = "bad uid: " + uid;
+ return;
+ }
+ final String pkgName = readCommonString(in, version);
+ if (pkgName == null) {
+ mReadError = "bad process package name";
+ return;
+ }
+ final int vers = in.readInt();
+ ProcessState proc = hadData ? mProcesses.get(procName, uid) : null;
+ if (proc != null) {
+ if (!proc.readFromParcel(in, false)) {
+ return;
+ }
+ } else {
+ proc = new ProcessState(this, pkgName, uid, vers, procName);
+ if (!proc.readFromParcel(in, true)) {
+ return;
+ }
+ }
+ if (DEBUG_PARCEL) Slog.d(TAG, "Adding process: " + procName + " " + uid
+ + " " + proc);
+ mProcesses.put(procName, uid, proc);
+ }
+ }
+
+ if (DEBUG_PARCEL) Slog.d(TAG, "Read " + mProcesses.getMap().size() + " processes");
+
+ int NPKG = in.readInt();
+ if (NPKG < 0) {
+ mReadError = "bad package count: " + NPKG;
+ return;
+ }
+ while (NPKG > 0) {
+ NPKG--;
+ final String pkgName = readCommonString(in, version);
+ if (pkgName == null) {
+ mReadError = "bad package name";
+ return;
+ }
+ int NUID = in.readInt();
+ if (NUID < 0) {
+ mReadError = "bad uid count: " + NUID;
+ return;
+ }
+ while (NUID > 0) {
+ NUID--;
+ final int uid = in.readInt();
+ if (uid < 0) {
+ mReadError = "bad uid: " + uid;
+ return;
+ }
+ int NVERS = in.readInt();
+ if (NVERS < 0) {
+ mReadError = "bad versions count: " + NVERS;
+ return;
+ }
+ while (NVERS > 0) {
+ NVERS--;
+ final int vers = in.readInt();
+ PackageState pkgState = new PackageState(pkgName, uid);
+ SparseArray<PackageState> vpkg = mPackages.get(pkgName, uid);
+ if (vpkg == null) {
+ vpkg = new SparseArray<PackageState>();
+ mPackages.put(pkgName, uid, vpkg);
+ }
+ vpkg.put(vers, pkgState);
+ int NPROCS = in.readInt();
+ if (NPROCS < 0) {
+ mReadError = "bad package process count: " + NPROCS;
+ return;
+ }
+ while (NPROCS > 0) {
+ NPROCS--;
+ String procName = readCommonString(in, version);
+ if (procName == null) {
+ mReadError = "bad package process name";
+ return;
+ }
+ int hasProc = in.readInt();
+ if (DEBUG_PARCEL) Slog.d(TAG, "Reading package " + pkgName + " " + uid
+ + " process " + procName + " hasProc=" + hasProc);
+ ProcessState commonProc = mProcesses.get(procName, uid);
+ if (DEBUG_PARCEL) Slog.d(TAG, "Got common proc " + procName + " " + uid
+ + ": " + commonProc);
+ if (commonProc == null) {
+ mReadError = "no common proc: " + procName;
+ return;
+ }
+ if (hasProc != 0) {
+ // The process for this package is unique to the package; we
+ // need to load it. We don't need to do anything about it if
+ // it is not unique because if someone later looks for it
+ // they will find and use it from the global procs.
+ ProcessState proc = hadData ? pkgState.mProcesses.get(procName) : null;
+ if (proc != null) {
+ if (!proc.readFromParcel(in, false)) {
+ return;
+ }
+ } else {
+ proc = new ProcessState(commonProc, pkgName, uid, vers, procName,
+ 0);
+ if (!proc.readFromParcel(in, true)) {
+ return;
+ }
+ }
+ if (DEBUG_PARCEL) Slog.d(TAG, "Adding package " + pkgName + " process: "
+ + procName + " " + uid + " " + proc);
+ pkgState.mProcesses.put(procName, proc);
+ } else {
+ if (DEBUG_PARCEL) Slog.d(TAG, "Adding package " + pkgName + " process: "
+ + procName + " " + uid + " " + commonProc);
+ pkgState.mProcesses.put(procName, commonProc);
+ }
+ }
+ int NSRVS = in.readInt();
+ if (NSRVS < 0) {
+ mReadError = "bad package service count: " + NSRVS;
+ return;
+ }
+ while (NSRVS > 0) {
+ NSRVS--;
+ String serviceName = in.readString();
+ if (serviceName == null) {
+ mReadError = "bad package service name";
+ return;
+ }
+ String processName = version > 9 ? readCommonString(in, version) : null;
+ ServiceState serv = hadData ? pkgState.mServices.get(serviceName) : null;
+ if (serv == null) {
+ serv = new ServiceState(this, pkgName, serviceName, processName, null);
+ }
+ if (!serv.readFromParcel(in)) {
+ return;
+ }
+ if (DEBUG_PARCEL) Slog.d(TAG, "Adding package " + pkgName + " service: "
+ + serviceName + " " + uid + " " + serv);
+ pkgState.mServices.put(serviceName, serv);
+ }
+ }
+ }
+ }
+
+ mIndexToCommonString = null;
+
+ if (DEBUG_PARCEL) Slog.d(TAG, "Successfully read procstats!");
+ }
+
+ public PackageState getPackageStateLocked(String packageName, int uid, int vers) {
+ SparseArray<PackageState> vpkg = mPackages.get(packageName, uid);
+ if (vpkg == null) {
+ vpkg = new SparseArray<PackageState>();
+ mPackages.put(packageName, uid, vpkg);
+ }
+ PackageState as = vpkg.get(vers);
+ if (as != null) {
+ return as;
+ }
+ as = new PackageState(packageName, uid);
+ vpkg.put(vers, as);
+ return as;
+ }
+
+ public ProcessState getProcessStateLocked(String packageName, int uid, int vers,
+ String processName) {
+ final PackageState pkgState = getPackageStateLocked(packageName, uid, vers);
+ ProcessState ps = pkgState.mProcesses.get(processName);
+ if (ps != null) {
+ return ps;
+ }
+ ProcessState commonProc = mProcesses.get(processName, uid);
+ if (commonProc == null) {
+ commonProc = new ProcessState(this, packageName, uid, vers, processName);
+ mProcesses.put(processName, uid, commonProc);
+ if (DEBUG) Slog.d(TAG, "GETPROC created new common " + commonProc);
+ }
+ if (!commonProc.isMultiPackage()) {
+ if (packageName.equals(commonProc.getPackage()) && vers == commonProc.getVersion()) {
+ // This common process is not in use by multiple packages, and
+ // is for the calling package, so we can just use it directly.
+ ps = commonProc;
+ if (DEBUG) Slog.d(TAG, "GETPROC also using for pkg " + commonProc);
+ } else {
+ if (DEBUG) Slog.d(TAG, "GETPROC need to split common proc!");
+ // This common process has not been in use by multiple packages,
+ // but it was created for a different package than the caller.
+ // We need to convert it to a multi-package process.
+ commonProc.setMultiPackage(true);
+ // To do this, we need to make two new process states, one a copy
+ // of the current state for the process under the original package
+ // name, and the second a free new process state for it as the
+ // new package name.
+ long now = SystemClock.uptimeMillis();
+ // First let's make a copy of the current process state and put
+ // that under the now unique state for its original package name.
+ final PackageState commonPkgState = getPackageStateLocked(commonProc.getPackage(),
+ uid, commonProc.getVersion());
+ if (commonPkgState != null) {
+ ProcessState cloned = commonProc.clone(now);
+ if (DEBUG) Slog.d(TAG, "GETPROC setting clone to pkg " + commonProc.getPackage()
+ + ": " + cloned);
+ commonPkgState.mProcesses.put(commonProc.getName(), cloned);
+ // If this has active services, we need to update their process pointer
+ // to point to the new package-specific process state.
+ for (int i=commonPkgState.mServices.size()-1; i>=0; i--) {
+ ServiceState ss = commonPkgState.mServices.valueAt(i);
+ if (ss.getProcess() == commonProc) {
+ if (DEBUG) Slog.d(TAG, "GETPROC switching service to cloned: " + ss);
+ ss.setProcess(cloned);
+ } else if (DEBUG) {
+ Slog.d(TAG, "GETPROC leaving proc of " + ss);
+ }
+ }
+ } else {
+ Slog.w(TAG, "Cloning proc state: no package state " + commonProc.getPackage()
+ + "/" + uid + " for proc " + commonProc.getName());
+ }
+ // And now make a fresh new process state for the new package name.
+ ps = new ProcessState(commonProc, packageName, uid, vers, processName, now);
+ if (DEBUG) Slog.d(TAG, "GETPROC created new pkg " + ps);
+ }
+ } else {
+ // The common process is for multiple packages, we need to create a
+ // separate object for the per-package data.
+ ps = new ProcessState(commonProc, packageName, uid, vers, processName,
+ SystemClock.uptimeMillis());
+ if (DEBUG) Slog.d(TAG, "GETPROC created new pkg " + ps);
+ }
+ pkgState.mProcesses.put(processName, ps);
+ if (DEBUG) Slog.d(TAG, "GETPROC adding new pkg " + ps);
+ return ps;
+ }
+
+ public ServiceState getServiceStateLocked(String packageName, int uid, int vers,
+ String processName, String className) {
+ final ProcessStats.PackageState as = getPackageStateLocked(packageName, uid, vers);
+ ServiceState ss = as.mServices.get(className);
+ if (ss != null) {
+ if (DEBUG) Slog.d(TAG, "GETSVC: returning existing " + ss);
+ return ss;
+ }
+ final ProcessState ps = processName != null
+ ? getProcessStateLocked(packageName, uid, vers, processName) : null;
+ ss = new ServiceState(this, packageName, className, processName, ps);
+ as.mServices.put(className, ss);
+ if (DEBUG) Slog.d(TAG, "GETSVC: creating " + ss + " in " + ps);
+ return ss;
+ }
+
+ public void dumpLocked(PrintWriter pw, String reqPackage, long now, boolean dumpSummary,
+ boolean dumpAll, boolean activeOnly) {
+ long totalTime = DumpUtils.dumpSingleTime(null, null, mMemFactorDurations, mMemFactor,
+ mStartTime, now);
+ boolean sepNeeded = false;
+ if (mSysMemUsage.getKeyCount() > 0) {
+ pw.println("System memory usage:");
+ mSysMemUsage.dump(pw, " ", ALL_SCREEN_ADJ, ALL_MEM_ADJ);
+ sepNeeded = true;
+ }
+ ArrayMap<String, SparseArray<SparseArray<PackageState>>> pkgMap = mPackages.getMap();
+ boolean printedHeader = false;
+ for (int ip=0; ip<pkgMap.size(); ip++) {
+ final String pkgName = pkgMap.keyAt(ip);
+ final SparseArray<SparseArray<PackageState>> uids = pkgMap.valueAt(ip);
+ for (int iu=0; iu<uids.size(); iu++) {
+ final int uid = uids.keyAt(iu);
+ final SparseArray<PackageState> vpkgs = uids.valueAt(iu);
+ for (int iv=0; iv<vpkgs.size(); iv++) {
+ final int vers = vpkgs.keyAt(iv);
+ final PackageState pkgState = vpkgs.valueAt(iv);
+ final int NPROCS = pkgState.mProcesses.size();
+ final int NSRVS = pkgState.mServices.size();
+ final boolean pkgMatch = reqPackage == null || reqPackage.equals(pkgName);
+ if (!pkgMatch) {
+ boolean procMatch = false;
+ for (int iproc=0; iproc<NPROCS; iproc++) {
+ ProcessState proc = pkgState.mProcesses.valueAt(iproc);
+ if (reqPackage.equals(proc.getName())) {
+ procMatch = true;
+ break;
+ }
+ }
+ if (!procMatch) {
+ continue;
+ }
+ }
+ if (NPROCS > 0 || NSRVS > 0) {
+ if (!printedHeader) {
+ if (sepNeeded) pw.println();
+ pw.println("Per-Package Stats:");
+ printedHeader = true;
+ sepNeeded = true;
+ }
+ pw.print(" * "); pw.print(pkgName); pw.print(" / ");
+ UserHandle.formatUid(pw, uid); pw.print(" / v");
+ pw.print(vers); pw.println(":");
+ }
+ if (!dumpSummary || dumpAll) {
+ for (int iproc=0; iproc<NPROCS; iproc++) {
+ ProcessState proc = pkgState.mProcesses.valueAt(iproc);
+ if (!pkgMatch && !reqPackage.equals(proc.getName())) {
+ continue;
+ }
+ if (activeOnly && !proc.isInUse()) {
+ pw.print(" (Not active: ");
+ pw.print(pkgState.mProcesses.keyAt(iproc)); pw.println(")");
+ continue;
+ }
+ pw.print(" Process ");
+ pw.print(pkgState.mProcesses.keyAt(iproc));
+ if (proc.getCommonProcess().isMultiPackage()) {
+ pw.print(" (multi, ");
+ } else {
+ pw.print(" (unique, ");
+ }
+ pw.print(proc.getDurationsBucketCount());
+ pw.print(" entries)");
+ pw.println(":");
+ proc.dumpProcessState(pw, " ", ALL_SCREEN_ADJ, ALL_MEM_ADJ,
+ ALL_PROC_STATES, now);
+ proc.dumpPss(pw, " ", ALL_SCREEN_ADJ, ALL_MEM_ADJ,
+ ALL_PROC_STATES);
+ proc.dumpInternalLocked(pw, " ", dumpAll);
+ }
+ } else {
+ ArrayList<ProcessState> procs = new ArrayList<ProcessState>();
+ for (int iproc=0; iproc<NPROCS; iproc++) {
+ ProcessState proc = pkgState.mProcesses.valueAt(iproc);
+ if (!pkgMatch && !reqPackage.equals(proc.getName())) {
+ continue;
+ }
+ if (activeOnly && !proc.isInUse()) {
+ continue;
+ }
+ procs.add(proc);
+ }
+ DumpUtils.dumpProcessSummaryLocked(pw, " ", procs,
+ ALL_SCREEN_ADJ, ALL_MEM_ADJ, NON_CACHED_PROC_STATES,
+ now, totalTime);
+ }
+ for (int isvc=0; isvc<NSRVS; isvc++) {
+ ServiceState svc = pkgState.mServices.valueAt(isvc);
+ if (!pkgMatch && !reqPackage.equals(svc.getProcessName())) {
+ continue;
+ }
+ if (activeOnly && !svc.isInUse()) {
+ pw.print(" (Not active: ");
+ pw.print(pkgState.mServices.keyAt(isvc)); pw.println(")");
+ continue;
+ }
+ if (dumpAll) {
+ pw.print(" Service ");
+ } else {
+ pw.print(" * ");
+ }
+ pw.print(pkgState.mServices.keyAt(isvc));
+ pw.println(":");
+ pw.print(" Process: "); pw.println(svc.getProcessName());
+ svc.dumpStats(pw, " ", " ", " ",
+ now, totalTime, dumpSummary, dumpAll);
+ }
+ }
+ }
+ }
+
+ ArrayMap<String, SparseArray<ProcessState>> procMap = mProcesses.getMap();
+ printedHeader = false;
+ int numShownProcs = 0, numTotalProcs = 0;
+ for (int ip=0; ip<procMap.size(); ip++) {
+ String procName = procMap.keyAt(ip);
+ SparseArray<ProcessState> uids = procMap.valueAt(ip);
+ for (int iu=0; iu<uids.size(); iu++) {
+ int uid = uids.keyAt(iu);
+ numTotalProcs++;
+ final ProcessState proc = uids.valueAt(iu);
+ if (proc.hasAnyData()) {
+ continue;
+ }
+ if (!proc.isMultiPackage()) {
+ continue;
+ }
+ if (reqPackage != null && !reqPackage.equals(procName)
+ && !reqPackage.equals(proc.getPackage())) {
+ continue;
+ }
+ numShownProcs++;
+ if (sepNeeded) {
+ pw.println();
+ }
+ sepNeeded = true;
+ if (!printedHeader) {
+ pw.println("Multi-Package Common Processes:");
+ printedHeader = true;
+ }
+ if (activeOnly && !proc.isInUse()) {
+ pw.print(" (Not active: "); pw.print(procName); pw.println(")");
+ continue;
+ }
+ pw.print(" * "); pw.print(procName); pw.print(" / ");
+ UserHandle.formatUid(pw, uid);
+ pw.print(" ("); pw.print(proc.getDurationsBucketCount());
+ pw.print(" entries)"); pw.println(":");
+ proc.dumpProcessState(pw, " ", ALL_SCREEN_ADJ, ALL_MEM_ADJ,
+ ALL_PROC_STATES, now);
+ proc.dumpPss(pw, " ", ALL_SCREEN_ADJ, ALL_MEM_ADJ, ALL_PROC_STATES);
+ proc.dumpInternalLocked(pw, " ", dumpAll);
+ }
+ }
+ if (dumpAll) {
+ pw.println();
+ pw.print(" Total procs: "); pw.print(numShownProcs);
+ pw.print(" shown of "); pw.print(numTotalProcs); pw.println(" total");
+ }
+
+ if (sepNeeded) {
+ pw.println();
+ }
+ if (dumpSummary) {
+ pw.println("Summary:");
+ dumpSummaryLocked(pw, reqPackage, now, activeOnly);
+ } else {
+ dumpTotalsLocked(pw, now);
+ }
+
+ if (dumpAll) {
+ pw.println();
+ pw.println("Internal state:");
+ /*
+ pw.print(" Num long arrays: "); pw.println(mLongs.size());
+ pw.print(" Next long entry: "); pw.println(mNextLong);
+ */
+ pw.print(" mRunning="); pw.println(mRunning);
+ }
+ }
+
+ public void dumpSummaryLocked(PrintWriter pw, String reqPackage, long now, boolean activeOnly) {
+ long totalTime = DumpUtils.dumpSingleTime(null, null, mMemFactorDurations, mMemFactor,
+ mStartTime, now);
+ dumpFilteredSummaryLocked(pw, null, " ", ALL_SCREEN_ADJ, ALL_MEM_ADJ,
+ ALL_PROC_STATES, NON_CACHED_PROC_STATES, now, totalTime, reqPackage, activeOnly);
+ pw.println();
+ dumpTotalsLocked(pw, now);
+ }
+
+ long printMemoryCategory(PrintWriter pw, String prefix, String label, double memWeight,
+ long totalTime, long curTotalMem, int samples) {
+ if (memWeight != 0) {
+ long mem = (long)(memWeight * 1024 / totalTime);
+ pw.print(prefix);
+ pw.print(label);
+ pw.print(": ");
+ DebugUtils.printSizeValue(pw, mem);
+ pw.print(" (");
+ pw.print(samples);
+ pw.print(" samples)");
+ pw.println();
+ return curTotalMem + mem;
+ }
+ return curTotalMem;
+ }
+
+ void dumpTotalsLocked(PrintWriter pw, long now) {
+ pw.println("Run time Stats:");
+ DumpUtils.dumpSingleTime(pw, " ", mMemFactorDurations, mMemFactor, mStartTime, now);
+ pw.println();
+ pw.println("Memory usage:");
+ TotalMemoryUseCollection totalMem = new TotalMemoryUseCollection(ALL_SCREEN_ADJ,
+ ALL_MEM_ADJ);
+ computeTotalMemoryUse(totalMem, now);
+ long totalPss = 0;
+ totalPss = printMemoryCategory(pw, " ", "Kernel ", totalMem.sysMemKernelWeight,
+ totalMem.totalTime, totalPss, totalMem.sysMemSamples);
+ totalPss = printMemoryCategory(pw, " ", "Native ", totalMem.sysMemNativeWeight,
+ totalMem.totalTime, totalPss, totalMem.sysMemSamples);
+ for (int i=0; i<STATE_COUNT; i++) {
+ // Skip restarting service state -- that is not actually a running process.
+ if (i != STATE_SERVICE_RESTARTING) {
+ totalPss = printMemoryCategory(pw, " ", DumpUtils.STATE_NAMES[i],
+ totalMem.processStateWeight[i], totalMem.totalTime, totalPss,
+ totalMem.processStateSamples[i]);
+ }
+ }
+ totalPss = printMemoryCategory(pw, " ", "Cached ", totalMem.sysMemCachedWeight,
+ totalMem.totalTime, totalPss, totalMem.sysMemSamples);
+ totalPss = printMemoryCategory(pw, " ", "Free ", totalMem.sysMemFreeWeight,
+ totalMem.totalTime, totalPss, totalMem.sysMemSamples);
+ totalPss = printMemoryCategory(pw, " ", "Z-Ram ", totalMem.sysMemZRamWeight,
+ totalMem.totalTime, totalPss, totalMem.sysMemSamples);
+ pw.print(" TOTAL : ");
+ DebugUtils.printSizeValue(pw, totalPss);
+ pw.println();
+ printMemoryCategory(pw, " ", DumpUtils.STATE_NAMES[STATE_SERVICE_RESTARTING],
+ totalMem.processStateWeight[STATE_SERVICE_RESTARTING], totalMem.totalTime, totalPss,
+ totalMem.processStateSamples[STATE_SERVICE_RESTARTING]);
+ pw.println();
+ pw.print(" Start time: ");
+ pw.print(DateFormat.format("yyyy-MM-dd HH:mm:ss", mTimePeriodStartClock));
+ pw.println();
+ pw.print(" Total elapsed time: ");
+ TimeUtils.formatDuration(
+ (mRunning ? SystemClock.elapsedRealtime() : mTimePeriodEndRealtime)
+ - mTimePeriodStartRealtime, pw);
+ boolean partial = true;
+ if ((mFlags&FLAG_SHUTDOWN) != 0) {
+ pw.print(" (shutdown)");
+ partial = false;
+ }
+ if ((mFlags&FLAG_SYSPROPS) != 0) {
+ pw.print(" (sysprops)");
+ partial = false;
+ }
+ if ((mFlags&FLAG_COMPLETE) != 0) {
+ pw.print(" (complete)");
+ partial = false;
+ }
+ if (partial) {
+ pw.print(" (partial)");
+ }
+ pw.print(' ');
+ pw.print(mRuntime);
+ pw.println();
+ }
+
+ void dumpFilteredSummaryLocked(PrintWriter pw, String header, String prefix,
+ int[] screenStates, int[] memStates, int[] procStates,
+ int[] sortProcStates, long now, long totalTime, String reqPackage, boolean activeOnly) {
+ ArrayList<ProcessState> procs = collectProcessesLocked(screenStates, memStates,
+ procStates, sortProcStates, now, reqPackage, activeOnly);
+ if (procs.size() > 0) {
+ if (header != null) {
+ pw.println();
+ pw.println(header);
+ }
+ DumpUtils.dumpProcessSummaryLocked(pw, prefix, procs, screenStates, memStates,
+ sortProcStates, now, totalTime);
+ }
+ }
+
+ public ArrayList<ProcessState> collectProcessesLocked(int[] screenStates, int[] memStates,
+ int[] procStates, int sortProcStates[], long now, String reqPackage,
+ boolean activeOnly) {
+ final ArraySet<ProcessState> foundProcs = new ArraySet<ProcessState>();
+ final ArrayMap<String, SparseArray<SparseArray<PackageState>>> pkgMap = mPackages.getMap();
+ for (int ip=0; ip<pkgMap.size(); ip++) {
+ final String pkgName = pkgMap.keyAt(ip);
+ final SparseArray<SparseArray<PackageState>> procs = pkgMap.valueAt(ip);
+ for (int iu=0; iu<procs.size(); iu++) {
+ final SparseArray<PackageState> vpkgs = procs.valueAt(iu);
+ final int NVERS = vpkgs.size();
+ for (int iv=0; iv<NVERS; iv++) {
+ final PackageState state = vpkgs.valueAt(iv);
+ final int NPROCS = state.mProcesses.size();
+ final boolean pkgMatch = reqPackage == null || reqPackage.equals(pkgName);
+ for (int iproc=0; iproc<NPROCS; iproc++) {
+ final ProcessState proc = state.mProcesses.valueAt(iproc);
+ if (!pkgMatch && !reqPackage.equals(proc.getName())) {
+ continue;
+ }
+ if (activeOnly && !proc.isInUse()) {
+ continue;
+ }
+ foundProcs.add(proc.getCommonProcess());
+ }
+ }
+ }
+ }
+ ArrayList<ProcessState> outProcs = new ArrayList<ProcessState>(foundProcs.size());
+ for (int i=0; i<foundProcs.size(); i++) {
+ ProcessState proc = foundProcs.valueAt(i);
+ if (proc.computeProcessTimeLocked(screenStates, memStates, procStates, now) > 0) {
+ outProcs.add(proc);
+ if (procStates != sortProcStates) {
+ proc.computeProcessTimeLocked(screenStates, memStates, sortProcStates, now);
+ }
+ }
+ }
+ Collections.sort(outProcs, ProcessState.COMPARATOR);
+ return outProcs;
+ }
+
+ public void dumpCheckinLocked(PrintWriter pw, String reqPackage) {
+ final long now = SystemClock.uptimeMillis();
+ final ArrayMap<String, SparseArray<SparseArray<PackageState>>> pkgMap = mPackages.getMap();
+ pw.println("vers,5");
+ pw.print("period,"); pw.print(mTimePeriodStartClockStr);
+ pw.print(","); pw.print(mTimePeriodStartRealtime); pw.print(",");
+ pw.print(mRunning ? SystemClock.elapsedRealtime() : mTimePeriodEndRealtime);
+ boolean partial = true;
+ if ((mFlags&FLAG_SHUTDOWN) != 0) {
+ pw.print(",shutdown");
+ partial = false;
+ }
+ if ((mFlags&FLAG_SYSPROPS) != 0) {
+ pw.print(",sysprops");
+ partial = false;
+ }
+ if ((mFlags&FLAG_COMPLETE) != 0) {
+ pw.print(",complete");
+ partial = false;
+ }
+ if (partial) {
+ pw.print(",partial");
+ }
+ pw.println();
+ pw.print("config,"); pw.println(mRuntime);
+ for (int ip=0; ip<pkgMap.size(); ip++) {
+ final String pkgName = pkgMap.keyAt(ip);
+ if (reqPackage != null && !reqPackage.equals(pkgName)) {
+ continue;
+ }
+ final SparseArray<SparseArray<PackageState>> uids = pkgMap.valueAt(ip);
+ for (int iu=0; iu<uids.size(); iu++) {
+ final int uid = uids.keyAt(iu);
+ final SparseArray<PackageState> vpkgs = uids.valueAt(iu);
+ for (int iv=0; iv<vpkgs.size(); iv++) {
+ final int vers = vpkgs.keyAt(iv);
+ final PackageState pkgState = vpkgs.valueAt(iv);
+ final int NPROCS = pkgState.mProcesses.size();
+ final int NSRVS = pkgState.mServices.size();
+ for (int iproc=0; iproc<NPROCS; iproc++) {
+ ProcessState proc = pkgState.mProcesses.valueAt(iproc);
+ proc.dumpPackageProcCheckin(pw, pkgName, uid, vers,
+ pkgState.mProcesses.keyAt(iproc), now);
+ }
+ for (int isvc=0; isvc<NSRVS; isvc++) {
+ final String serviceName = DumpUtils.collapseString(pkgName,
+ pkgState.mServices.keyAt(isvc));
+ final ServiceState svc = pkgState.mServices.valueAt(isvc);
+ svc.dumpTimesCheckin(pw, pkgName, uid, vers, serviceName, now);
+ }
+ }
+ }
+ }
+
+ ArrayMap<String, SparseArray<ProcessState>> procMap = mProcesses.getMap();
+ for (int ip=0; ip<procMap.size(); ip++) {
+ String procName = procMap.keyAt(ip);
+ SparseArray<ProcessState> uids = procMap.valueAt(ip);
+ for (int iu=0; iu<uids.size(); iu++) {
+ final int uid = uids.keyAt(iu);
+ final ProcessState procState = uids.valueAt(iu);
+ procState.dumpProcCheckin(pw, procName, uid, now);
+ }
+ }
+ pw.print("total");
+ DumpUtils.dumpAdjTimesCheckin(pw, ",", mMemFactorDurations, mMemFactor, mStartTime, now);
+ pw.println();
+ final int sysMemUsageCount = mSysMemUsage.getKeyCount();
+ if (sysMemUsageCount > 0) {
+ pw.print("sysmemusage");
+ for (int i=0; i<sysMemUsageCount; i++) {
+ final int key = mSysMemUsage.getKeyAt(i);
+ final int type = SparseMappingTable.getIdFromKey(key);
+ pw.print(",");
+ DumpUtils.printProcStateTag(pw, type);
+ for (int j=SYS_MEM_USAGE_SAMPLE_COUNT; j<SYS_MEM_USAGE_COUNT; j++) {
+ if (j > SYS_MEM_USAGE_CACHED_MINIMUM) {
+ pw.print(":");
+ }
+ pw.print(mSysMemUsage.getValue(key, j));
+ }
+ }
+ }
+ pw.println();
+ TotalMemoryUseCollection totalMem = new TotalMemoryUseCollection(ALL_SCREEN_ADJ,
+ ALL_MEM_ADJ);
+ computeTotalMemoryUse(totalMem, now);
+ pw.print("weights,");
+ pw.print(totalMem.totalTime);
+ pw.print(",");
+ pw.print(totalMem.sysMemCachedWeight);
+ pw.print(":");
+ pw.print(totalMem.sysMemSamples);
+ pw.print(",");
+ pw.print(totalMem.sysMemFreeWeight);
+ pw.print(":");
+ pw.print(totalMem.sysMemSamples);
+ pw.print(",");
+ pw.print(totalMem.sysMemZRamWeight);
+ pw.print(":");
+ pw.print(totalMem.sysMemSamples);
+ pw.print(",");
+ pw.print(totalMem.sysMemKernelWeight);
+ pw.print(":");
+ pw.print(totalMem.sysMemSamples);
+ pw.print(",");
+ pw.print(totalMem.sysMemNativeWeight);
+ pw.print(":");
+ pw.print(totalMem.sysMemSamples);
+ for (int i=0; i<STATE_COUNT; i++) {
+ pw.print(",");
+ pw.print(totalMem.processStateWeight[i]);
+ pw.print(":");
+ pw.print(totalMem.processStateSamples[i]);
+ }
+ pw.println();
+ }
+
+
+ final public static class ProcessStateHolder {
+ public final int appVersion;
+ public ProcessState state;
+
+ public ProcessStateHolder(int _appVersion) {
+ appVersion = _appVersion;
+ }
+ }
+
+ public static final class PackageState {
+ public final ArrayMap<String, ProcessState> mProcesses
+ = new ArrayMap<String, ProcessState>();
+ public final ArrayMap<String, ServiceState> mServices
+ = new ArrayMap<String, ServiceState>();
+ public final String mPackageName;
+ public final int mUid;
+
+ public PackageState(String packageName, int uid) {
+ mUid = uid;
+ mPackageName = packageName;
+ }
+ }
+
+ public static final class ProcessDataCollection {
+ final int[] screenStates;
+ final int[] memStates;
+ final int[] procStates;
+
+ public long totalTime;
+ public long numPss;
+ public long minPss;
+ public long avgPss;
+ public long maxPss;
+ public long minUss;
+ public long avgUss;
+ public long maxUss;
+
+ public ProcessDataCollection(int[] _screenStates, int[] _memStates, int[] _procStates) {
+ screenStates = _screenStates;
+ memStates = _memStates;
+ procStates = _procStates;
+ }
+
+ void print(PrintWriter pw, long overallTime, boolean full) {
+ if (totalTime > overallTime) {
+ pw.print("*");
+ }
+ DumpUtils.printPercent(pw, (double) totalTime / (double) overallTime);
+ if (numPss > 0) {
+ pw.print(" (");
+ DebugUtils.printSizeValue(pw, minPss * 1024);
+ pw.print("-");
+ DebugUtils.printSizeValue(pw, avgPss * 1024);
+ pw.print("-");
+ DebugUtils.printSizeValue(pw, maxPss * 1024);
+ pw.print("/");
+ DebugUtils.printSizeValue(pw, minUss * 1024);
+ pw.print("-");
+ DebugUtils.printSizeValue(pw, avgUss * 1024);
+ pw.print("-");
+ DebugUtils.printSizeValue(pw, maxUss * 1024);
+ if (full) {
+ pw.print(" over ");
+ pw.print(numPss);
+ }
+ pw.print(")");
+ }
+ }
+ }
+
+ public static class TotalMemoryUseCollection {
+ final int[] screenStates;
+ final int[] memStates;
+
+ public TotalMemoryUseCollection(int[] _screenStates, int[] _memStates) {
+ screenStates = _screenStates;
+ memStates = _memStates;
+ }
+
+ public long totalTime;
+ public long[] processStatePss = new long[STATE_COUNT];
+ public double[] processStateWeight = new double[STATE_COUNT];
+ public long[] processStateTime = new long[STATE_COUNT];
+ public int[] processStateSamples = new int[STATE_COUNT];
+ public long[] sysMemUsage = new long[SYS_MEM_USAGE_COUNT];
+ public double sysMemCachedWeight;
+ public double sysMemFreeWeight;
+ public double sysMemZRamWeight;
+ public double sysMemKernelWeight;
+ public double sysMemNativeWeight;
+ public int sysMemSamples;
+ }
+
+}
diff --git a/core/java/com/android/internal/app/procstats/PssTable.java b/core/java/com/android/internal/app/procstats/PssTable.java
new file mode 100644
index 0000000..b6df983
--- /dev/null
+++ b/core/java/com/android/internal/app/procstats/PssTable.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2013 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.app.procstats;
+
+import static com.android.internal.app.procstats.ProcessStats.PSS_SAMPLE_COUNT;
+import static com.android.internal.app.procstats.ProcessStats.PSS_MINIMUM;
+import static com.android.internal.app.procstats.ProcessStats.PSS_AVERAGE;
+import static com.android.internal.app.procstats.ProcessStats.PSS_MAXIMUM;
+import static com.android.internal.app.procstats.ProcessStats.PSS_USS_MINIMUM;
+import static com.android.internal.app.procstats.ProcessStats.PSS_USS_AVERAGE;
+import static com.android.internal.app.procstats.ProcessStats.PSS_USS_MAXIMUM;
+import static com.android.internal.app.procstats.ProcessStats.PSS_COUNT;
+
+/**
+ * Class to accumulate PSS data.
+ */
+public class PssTable extends SparseMappingTable.Table {
+ /**
+ * Construct the PssTable with 'tableData' as backing store
+ * for the longs data.
+ */
+ public PssTable(SparseMappingTable tableData) {
+ super(tableData);
+ }
+
+ /**
+ * Merge the the values from the other table into this one.
+ */
+ public void mergeStats(PssTable that) {
+ final int N = that.getKeyCount();
+ for (int i=0; i<N; i++) {
+ final int key = that.getKeyAt(i);
+ final int state = SparseMappingTable.getIdFromKey(key);
+ mergeStats(state, (int)that.getValue(key, PSS_SAMPLE_COUNT),
+ that.getValue(key, PSS_MINIMUM),
+ that.getValue(key, PSS_AVERAGE),
+ that.getValue(key, PSS_MAXIMUM),
+ that.getValue(key, PSS_USS_MINIMUM),
+ that.getValue(key, PSS_USS_AVERAGE),
+ that.getValue(key, PSS_USS_MAXIMUM));
+ }
+ }
+
+ /**
+ * Merge the supplied PSS data in. The new min pss will be the minimum of the existing
+ * one and the new one, the average will now incorporate the new average, etc.
+ */
+ public void mergeStats(int state, int inCount, long minPss, long avgPss, long maxPss,
+ long minUss, long avgUss, long maxUss) {
+ final int key = getOrAddKey((byte)state, PSS_COUNT);
+ final long count = getValue(key, PSS_SAMPLE_COUNT);
+ if (count == 0) {
+ setValue(key, PSS_SAMPLE_COUNT, inCount);
+ setValue(key, PSS_MINIMUM, minPss);
+ setValue(key, PSS_AVERAGE, avgPss);
+ setValue(key, PSS_MAXIMUM, maxPss);
+ setValue(key, PSS_USS_MINIMUM, minUss);
+ setValue(key, PSS_USS_AVERAGE, avgUss);
+ setValue(key, PSS_USS_MAXIMUM, maxUss);
+ } else {
+ setValue(key, PSS_SAMPLE_COUNT, count + inCount);
+
+ long val;
+
+ val = getValue(key, PSS_MINIMUM);
+ if (val > minPss) {
+ setValue(key, PSS_MINIMUM, minPss);
+ }
+
+ val = getValue(key, PSS_AVERAGE);
+ setValue(key, PSS_AVERAGE,
+ (long)(((val*(double)count)+(avgPss*(double)inCount)) / (count+inCount)));
+
+ val = getValue(key, PSS_MAXIMUM);
+ if (val < maxPss) {
+ setValue(key, PSS_MAXIMUM, maxPss);
+ }
+
+ val = getValue(key, PSS_USS_MINIMUM);
+ if (val > minUss) {
+ setValue(key, PSS_USS_MINIMUM, minUss);
+ }
+
+ val = getValue(key, PSS_USS_AVERAGE);
+ setValue(key, PSS_AVERAGE,
+ (long)(((val*(double)count)+(avgUss*(double)inCount)) / (count+inCount)));
+
+ val = getValue(key, PSS_USS_MAXIMUM);
+ if (val < maxUss) {
+ setValue(key, PSS_USS_MAXIMUM, maxUss);
+ }
+ }
+ }
+}
diff --git a/core/java/com/android/internal/app/procstats/ServiceState.java b/core/java/com/android/internal/app/procstats/ServiceState.java
new file mode 100644
index 0000000..2e11c43
--- /dev/null
+++ b/core/java/com/android/internal/app/procstats/ServiceState.java
@@ -0,0 +1,502 @@
+/*
+ * Copyright (C) 2013 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.app.procstats;
+
+
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.SystemClock;
+import android.os.SystemProperties;
+import android.os.UserHandle;
+import android.text.format.DateFormat;
+import android.util.ArrayMap;
+import android.util.ArraySet;
+import android.util.DebugUtils;
+import android.util.Log;
+import android.util.Slog;
+import android.util.SparseArray;
+import android.util.TimeUtils;
+
+import com.android.internal.app.procstats.ProcessStats;
+import static com.android.internal.app.procstats.ProcessStats.STATE_NOTHING;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Objects;
+
+public final class ServiceState {
+ private static final String TAG = "ProcessStats";
+ private static final boolean DEBUG = false;
+
+ public static final int SERVICE_RUN = 0;
+ public static final int SERVICE_STARTED = 1;
+ public static final int SERVICE_BOUND = 2;
+ public static final int SERVICE_EXEC = 3;
+ public static final int SERVICE_COUNT = 4;
+
+ private final String mPackage;
+ private final String mProcessName;
+ private final String mName;
+ private final DurationsTable mDurations;
+
+ private ProcessState mProc;
+ private Object mOwner;
+
+ private int mRunCount;
+ private int mRunState = STATE_NOTHING;
+ private long mRunStartTime;
+
+ private boolean mStarted;
+ private boolean mRestarting;
+ private int mStartedCount;
+ private int mStartedState = STATE_NOTHING;
+ private long mStartedStartTime;
+
+ private int mBoundCount;
+ private int mBoundState = STATE_NOTHING;
+ private long mBoundStartTime;
+
+ private int mExecCount;
+ private int mExecState = STATE_NOTHING;
+ private long mExecStartTime;
+
+ public ServiceState(ProcessStats processStats, String pkg, String name,
+ String processName, ProcessState proc) {
+ mPackage = pkg;
+ mName = name;
+ mProcessName = processName;
+ mProc = proc;
+ mDurations = new DurationsTable(processStats.mTableData);
+ }
+
+ public String getPackage() {
+ return mPackage;
+ }
+
+ public String getProcessName() {
+ return mProcessName;
+ }
+
+ public String getName() {
+ return mName;
+ }
+
+ public ProcessState getProcess() {
+ return mProc;
+ }
+
+ public void setProcess(ProcessState proc) {
+ mProc = proc;
+ }
+
+ public void setMemFactor(int memFactor, long now) {
+ if (isRestarting()) {
+ setRestarting(true, memFactor, now);
+ } else if (isInUse()) {
+ if (mStartedState != ProcessStats.STATE_NOTHING) {
+ setStarted(true, memFactor, now);
+ }
+ if (mBoundState != ProcessStats.STATE_NOTHING) {
+ setBound(true, memFactor, now);
+ }
+ if (mExecState != ProcessStats.STATE_NOTHING) {
+ setExecuting(true, memFactor, now);
+ }
+ }
+ }
+
+ public void applyNewOwner(Object newOwner) {
+ if (mOwner != newOwner) {
+ if (mOwner == null) {
+ mOwner = newOwner;
+ mProc.incActiveServices(mName);
+ } else {
+ // There was already an old owner, reset this object for its
+ // new owner.
+ mOwner = newOwner;
+ if (mStarted || mBoundState != STATE_NOTHING || mExecState != STATE_NOTHING) {
+ long now = SystemClock.uptimeMillis();
+ if (mStarted) {
+ if (DEBUG) Slog.d(TAG, "Service has new owner " + newOwner
+ + " from " + mOwner + " while started: pkg="
+ + mPackage + " service=" + mName + " proc=" + mProc);
+ setStarted(false, 0, now);
+ }
+ if (mBoundState != STATE_NOTHING) {
+ if (DEBUG) Slog.d(TAG, "Service has new owner " + newOwner
+ + " from " + mOwner + " while bound: pkg="
+ + mPackage + " service=" + mName + " proc=" + mProc);
+ setBound(false, 0, now);
+ }
+ if (mExecState != STATE_NOTHING) {
+ if (DEBUG) Slog.d(TAG, "Service has new owner " + newOwner
+ + " from " + mOwner + " while executing: pkg="
+ + mPackage + " service=" + mName + " proc=" + mProc);
+ setExecuting(false, 0, now);
+ }
+ }
+ }
+ }
+ }
+
+ public void clearCurrentOwner(Object owner, boolean silently) {
+ if (mOwner == owner) {
+ mProc.decActiveServices(mName);
+ if (mStarted || mBoundState != STATE_NOTHING || mExecState != STATE_NOTHING) {
+ long now = SystemClock.uptimeMillis();
+ if (mStarted) {
+ if (!silently) {
+ Slog.wtfStack(TAG, "Service owner " + owner
+ + " cleared while started: pkg=" + mPackage + " service="
+ + mName + " proc=" + mProc);
+ }
+ setStarted(false, 0, now);
+ }
+ if (mBoundState != STATE_NOTHING) {
+ if (!silently) {
+ Slog.wtfStack(TAG, "Service owner " + owner
+ + " cleared while bound: pkg=" + mPackage + " service="
+ + mName + " proc=" + mProc);
+ }
+ setBound(false, 0, now);
+ }
+ if (mExecState != STATE_NOTHING) {
+ if (!silently) {
+ Slog.wtfStack(TAG, "Service owner " + owner
+ + " cleared while exec: pkg=" + mPackage + " service="
+ + mName + " proc=" + mProc);
+ }
+ setExecuting(false, 0, now);
+ }
+ }
+ mOwner = null;
+ }
+ }
+
+ public boolean isInUse() {
+ return mOwner != null || mRestarting;
+ }
+
+ public boolean isRestarting() {
+ return mRestarting;
+ }
+
+ public void add(ServiceState other) {
+ mDurations.addDurations(other.mDurations);
+ mRunCount += other.mRunCount;
+ mStartedCount += other.mStartedCount;
+ mBoundCount += other.mBoundCount;
+ mExecCount += other.mExecCount;
+ }
+
+ public void resetSafely(long now) {
+ mDurations.resetTable();
+ mRunCount = mRunState != STATE_NOTHING ? 1 : 0;
+ mStartedCount = mStartedState != STATE_NOTHING ? 1 : 0;
+ mBoundCount = mBoundState != STATE_NOTHING ? 1 : 0;
+ mExecCount = mExecState != STATE_NOTHING ? 1 : 0;
+ mRunStartTime = mStartedStartTime = mBoundStartTime = mExecStartTime = now;
+ }
+
+ public void writeToParcel(Parcel out, long now) {
+ mDurations.writeToParcel(out);
+ out.writeInt(mRunCount);
+ out.writeInt(mStartedCount);
+ out.writeInt(mBoundCount);
+ out.writeInt(mExecCount);
+ }
+
+ public boolean readFromParcel(Parcel in) {
+ if (!mDurations.readFromParcel(in)) {
+ return false;
+ }
+ mRunCount = in.readInt();
+ mStartedCount = in.readInt();
+ mBoundCount = in.readInt();
+ mExecCount = in.readInt();
+ return true;
+ }
+
+ public void commitStateTime(long now) {
+ if (mRunState != STATE_NOTHING) {
+ mDurations.addDuration(SERVICE_RUN + (mRunState*SERVICE_COUNT),
+ now - mRunStartTime);
+ mRunStartTime = now;
+ }
+ if (mStartedState != STATE_NOTHING) {
+ mDurations.addDuration(SERVICE_STARTED + (mStartedState*SERVICE_COUNT),
+ now - mStartedStartTime);
+ mStartedStartTime = now;
+ }
+ if (mBoundState != STATE_NOTHING) {
+ mDurations.addDuration(SERVICE_BOUND + (mBoundState*SERVICE_COUNT),
+ now - mBoundStartTime);
+ mBoundStartTime = now;
+ }
+ if (mExecState != STATE_NOTHING) {
+ mDurations.addDuration(SERVICE_EXEC + (mExecState*SERVICE_COUNT),
+ now - mExecStartTime);
+ mExecStartTime = now;
+ }
+ }
+
+ private void updateRunning(int memFactor, long now) {
+ final int state = (mStartedState != STATE_NOTHING || mBoundState != STATE_NOTHING
+ || mExecState != STATE_NOTHING) ? memFactor : STATE_NOTHING;
+ if (mRunState != state) {
+ if (mRunState != STATE_NOTHING) {
+ mDurations.addDuration(SERVICE_RUN + (mRunState*SERVICE_COUNT),
+ now - mRunStartTime);
+ } else if (state != STATE_NOTHING) {
+ mRunCount++;
+ }
+ mRunState = state;
+ mRunStartTime = now;
+ }
+ }
+
+ public void setStarted(boolean started, int memFactor, long now) {
+ if (mOwner == null) {
+ Slog.wtf(TAG, "Starting service " + this + " without owner");
+ }
+ mStarted = started;
+ updateStartedState(memFactor, now);
+ }
+
+ public void setRestarting(boolean restarting, int memFactor, long now) {
+ mRestarting = restarting;
+ updateStartedState(memFactor, now);
+ }
+
+ public void updateStartedState(int memFactor, long now) {
+ final boolean wasStarted = mStartedState != STATE_NOTHING;
+ final boolean started = mStarted || mRestarting;
+ final int state = started ? memFactor : STATE_NOTHING;
+ if (mStartedState != state) {
+ if (mStartedState != STATE_NOTHING) {
+ mDurations.addDuration(SERVICE_STARTED + (mStartedState*SERVICE_COUNT),
+ now - mStartedStartTime);
+ } else if (started) {
+ mStartedCount++;
+ }
+ mStartedState = state;
+ mStartedStartTime = now;
+ mProc = mProc.pullFixedProc(mPackage);
+ if (wasStarted != started) {
+ if (started) {
+ mProc.incStartedServices(memFactor, now, mName);
+ } else {
+ mProc.decStartedServices(memFactor, now, mName);
+ }
+ }
+ updateRunning(memFactor, now);
+ }
+ }
+
+ public void setBound(boolean bound, int memFactor, long now) {
+ if (mOwner == null) {
+ Slog.wtf(TAG, "Binding service " + this + " without owner");
+ }
+ final int state = bound ? memFactor : STATE_NOTHING;
+ if (mBoundState != state) {
+ if (mBoundState != STATE_NOTHING) {
+ mDurations.addDuration(SERVICE_BOUND + (mBoundState*SERVICE_COUNT),
+ now - mBoundStartTime);
+ } else if (bound) {
+ mBoundCount++;
+ }
+ mBoundState = state;
+ mBoundStartTime = now;
+ updateRunning(memFactor, now);
+ }
+ }
+
+ public void setExecuting(boolean executing, int memFactor, long now) {
+ if (mOwner == null) {
+ Slog.wtf(TAG, "Executing service " + this + " without owner");
+ }
+ final int state = executing ? memFactor : STATE_NOTHING;
+ if (mExecState != state) {
+ if (mExecState != STATE_NOTHING) {
+ mDurations.addDuration(SERVICE_EXEC + (mExecState*SERVICE_COUNT),
+ now - mExecStartTime);
+ } else if (executing) {
+ mExecCount++;
+ }
+ mExecState = state;
+ mExecStartTime = now;
+ updateRunning(memFactor, now);
+ }
+ }
+
+ public long getDuration(int opType, int curState, long startTime, int memFactor,
+ long now) {
+ int state = opType + (memFactor*SERVICE_COUNT);
+ long time = mDurations.getValueForId((byte)state);
+ if (curState == memFactor) {
+ time += now - startTime;
+ }
+ return time;
+ }
+
+ public void dumpStats(PrintWriter pw, String prefix, String prefixInner, String headerPrefix,
+ long now, long totalTime, boolean dumpSummary, boolean dumpAll) {
+ dumpStats(pw, prefix, prefixInner, headerPrefix, "Running",
+ mRunCount, ServiceState.SERVICE_RUN, mRunState,
+ mRunStartTime, now, totalTime, !dumpSummary || dumpAll);
+ dumpStats(pw, prefix, prefixInner, headerPrefix, "Started",
+ mStartedCount, ServiceState.SERVICE_STARTED, mStartedState,
+ mStartedStartTime, now, totalTime, !dumpSummary || dumpAll);
+ dumpStats(pw, prefix, prefixInner, headerPrefix, "Bound",
+ mBoundCount, ServiceState.SERVICE_BOUND, mBoundState,
+ mBoundStartTime, now, totalTime, !dumpSummary || dumpAll);
+ dumpStats(pw, prefix, prefixInner, headerPrefix, "Executing",
+ mExecCount, ServiceState.SERVICE_EXEC, mExecState,
+ mExecStartTime, now, totalTime, !dumpSummary || dumpAll);
+ if (dumpAll) {
+ if (mOwner != null) {
+ pw.print(" mOwner="); pw.println(mOwner);
+ }
+ if (mStarted || mRestarting) {
+ pw.print(" mStarted="); pw.print(mStarted);
+ pw.print(" mRestarting="); pw.println(mRestarting);
+ }
+ }
+ }
+
+ private void dumpStats(PrintWriter pw, String prefix, String prefixInner,
+ String headerPrefix, String header,
+ int count, int serviceType, int state, long startTime, long now, long totalTime,
+ boolean dumpAll) {
+ if (count != 0) {
+ if (dumpAll) {
+ pw.print(prefix); pw.print(header);
+ pw.print(" op count "); pw.print(count); pw.println(":");
+ dumpTime(pw, prefixInner, serviceType, state, startTime, now);
+ } else {
+ long myTime = dumpTime(null, null, serviceType, state, startTime, now);
+ pw.print(prefix); pw.print(headerPrefix); pw.print(header);
+ pw.print(" count "); pw.print(count);
+ pw.print(" / time ");
+ DumpUtils.printPercent(pw, (double)myTime/(double)totalTime);
+ pw.println();
+ }
+ }
+ }
+
+ public long dumpTime(PrintWriter pw, String prefix,
+ int serviceType, int curState, long curStartTime, long now) {
+ long totalTime = 0;
+ int printedScreen = -1;
+ for (int iscreen=0; iscreen<ProcessStats.ADJ_COUNT; iscreen+=ProcessStats.ADJ_SCREEN_MOD) {
+ int printedMem = -1;
+ for (int imem=0; imem<ProcessStats.ADJ_MEM_FACTOR_COUNT; imem++) {
+ int state = imem+iscreen;
+ long time = getDuration(serviceType, curState, curStartTime, state, now);
+ String running = "";
+ if (curState == state && pw != null) {
+ running = " (running)";
+ }
+ if (time != 0) {
+ if (pw != null) {
+ pw.print(prefix);
+ DumpUtils.printScreenLabel(pw, printedScreen != iscreen
+ ? iscreen : STATE_NOTHING);
+ printedScreen = iscreen;
+ DumpUtils.printMemLabel(pw, printedMem != imem ? imem : STATE_NOTHING,
+ (char)0);
+ printedMem = imem;
+ pw.print(": ");
+ TimeUtils.formatDuration(time, pw); pw.println(running);
+ }
+ totalTime += time;
+ }
+ }
+ }
+ if (totalTime != 0 && pw != null) {
+ pw.print(prefix);
+ pw.print(" TOTAL: ");
+ TimeUtils.formatDuration(totalTime, pw);
+ pw.println();
+ }
+ return totalTime;
+ }
+
+ public void dumpTimesCheckin(PrintWriter pw, String pkgName, int uid, int vers,
+ String serviceName, long now) {
+ dumpTimeCheckin(pw, "pkgsvc-run", pkgName, uid, vers, serviceName,
+ ServiceState.SERVICE_RUN, mRunCount, mRunState, mRunStartTime, now);
+ dumpTimeCheckin(pw, "pkgsvc-start", pkgName, uid, vers, serviceName,
+ ServiceState.SERVICE_STARTED, mStartedCount, mStartedState, mStartedStartTime, now);
+ dumpTimeCheckin(pw, "pkgsvc-bound", pkgName, uid, vers, serviceName,
+ ServiceState.SERVICE_BOUND, mBoundCount, mBoundState, mBoundStartTime, now);
+ dumpTimeCheckin(pw, "pkgsvc-exec", pkgName, uid, vers, serviceName,
+ ServiceState.SERVICE_EXEC, mExecCount, mExecState, mExecStartTime, now);
+ }
+
+ private void dumpTimeCheckin(PrintWriter pw, String label, String packageName,
+ int uid, int vers, String serviceName, int serviceType, int opCount,
+ int curState, long curStartTime, long now) {
+ if (opCount <= 0) {
+ return;
+ }
+ pw.print(label);
+ pw.print(",");
+ pw.print(packageName);
+ pw.print(",");
+ pw.print(uid);
+ pw.print(",");
+ pw.print(vers);
+ pw.print(",");
+ pw.print(serviceName);
+ pw.print(",");
+ pw.print(opCount);
+ boolean didCurState = false;
+ final int N = mDurations.getKeyCount();
+ for (int i=0; i<N; i++) {
+ final int key = mDurations.getKeyAt(i);
+ long time = mDurations.getValue(key);
+ int type = SparseMappingTable.getIdFromKey(key);
+ int memFactor = type / ServiceState.SERVICE_COUNT;
+ type %= ServiceState.SERVICE_COUNT;
+ if (type != serviceType) {
+ continue;
+ }
+ if (curState == memFactor) {
+ didCurState = true;
+ time += now - curStartTime;
+ }
+ DumpUtils.printAdjTagAndValue(pw, memFactor, time);
+ }
+ if (!didCurState && curState != STATE_NOTHING) {
+ DumpUtils.printAdjTagAndValue(pw, curState, now - curStartTime);
+ }
+ pw.println();
+ }
+
+
+ public String toString() {
+ return "ServiceState{" + Integer.toHexString(System.identityHashCode(this))
+ + " " + mName + " pkg=" + mPackage + " proc="
+ + Integer.toHexString(System.identityHashCode(this)) + "}";
+ }
+}
diff --git a/core/java/com/android/internal/app/procstats/SparseMappingTable.java b/core/java/com/android/internal/app/procstats/SparseMappingTable.java
new file mode 100644
index 0000000..64c49a2
--- /dev/null
+++ b/core/java/com/android/internal/app/procstats/SparseMappingTable.java
@@ -0,0 +1,627 @@
+/*
+ * Copyright (C) 2013 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.app.procstats;
+
+import android.os.Build;
+import android.os.Parcel;
+import android.util.Slog;
+import libcore.util.EmptyArray;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+
+import com.android.internal.util.GrowingArrayUtils;
+
+/**
+ * Class that contains a set of tables mapping byte ids to long values.
+ *
+ * This class is used to store the ProcessStats data. This data happens to be
+ * a set of very sparse tables, that is mostly append or overwrite, with infrequent
+ * resets of the data.
+ *
+ * Data is stored as a list of large long[] arrays containing the actual values. There are a
+ * set of Table objects that each contain a small array mapping the byte IDs to a position
+ * in the larger arrays.
+ *
+ * The data itself is either a single long value or a range of long values which are always
+ * stored continguously in one of the long arrays. When the caller allocates a slot with
+ * getOrAddKey, an int key is returned. That key can be re-retreived with getKey without
+ * allocating the value. The data can then be set or retrieved with that key.
+ */
+public class SparseMappingTable {
+ private static final String TAG = "SparseMappingTable";
+
+ // How big each array is.
+ public static final int ARRAY_SIZE = 4096;
+
+ public static final int INVALID_KEY = 0xffffffff;
+
+ // Where the "type"/"state" part of the data appears in an offset integer.
+ private static final int ID_SHIFT = 0;
+ private static final int ID_MASK = 0xff;
+ // Where the "which array" part of the data appears in an offset integer.
+ private static final int ARRAY_SHIFT = 8;
+ private static final int ARRAY_MASK = 0xff;
+ // Where the "index into array" part of the data appears in an offset integer.
+ private static final int INDEX_SHIFT = 16;
+ private static final int INDEX_MASK = 0xffff;
+
+ private int mSequence;
+ private int mNextIndex;
+ private final ArrayList<long[]> mLongs = new ArrayList<long[]>();
+
+ /**
+ * A table of data as stored in a SparseMappingTable.
+ */
+ public static class Table {
+ // When mSequence is this this our data better be empty
+ private static final int UNINITIALIZED_SEQUENCE = -1;
+
+ private SparseMappingTable mParent;
+ private int mSequence = UNINITIALIZED_SEQUENCE;
+ private int[] mTable;
+ private int mSize;
+
+ public Table(SparseMappingTable parent) {
+ mParent = parent;
+ mSequence = parent.mSequence;
+ }
+
+ /**
+ * Pulls the data from 'copyFrom' and stores it in our own longs table.
+ *
+ * @param copyFrom The Table to copy from
+ * @param valueCount The number of values to copy for each key
+ */
+ public void copyFrom(Table copyFrom, int valueCount) {
+ mTable = null;
+ mSize = 0;
+
+ final int N = copyFrom.getKeyCount();
+ for (int i=0; i<N; i++) {
+ final int theirKey = copyFrom.getKeyAt(i);
+ final long[] theirLongs = copyFrom.mParent.mLongs.get(getArrayFromKey(theirKey));
+
+ final byte id = SparseMappingTable.getIdFromKey(theirKey);
+
+ final int myKey = this.getOrAddKey((byte)id, valueCount);
+ final long[] myLongs = mParent.mLongs.get(getArrayFromKey(myKey));
+
+ System.arraycopy(theirLongs, getIndexFromKey(theirKey),
+ myLongs, getIndexFromKey(myKey), valueCount);
+ }
+ }
+
+ /**
+ * Allocates data in the buffer, and stores that key in the mapping for this
+ * table.
+ *
+ * @param id The id of the item (will be used in making the key)
+ * @param count The number of bytes to allocate. Must be less than
+ * SparseMappingTable.ARRAY_SIZE.
+ *
+ * @return The 'key' for this data value, which contains both the id itself
+ * and the location in the long arrays that the data is actually stored
+ * but should be considered opaque to the caller.
+ */
+ public int getOrAddKey(byte id, int count) {
+ // This is the only place we add data to mParent.mLongs, so this is the time
+ // to update our sequence to match there.
+ if (mSequence == UNINITIALIZED_SEQUENCE) {
+ mSequence = mParent.mSequence;
+ }
+
+ assertConsistency();
+
+ final int idx = binarySearch(id);
+ if (idx >= 0) {
+ // Found
+ return mTable[idx];
+ } else {
+ // Not found. Need to allocate it.
+
+ // Get an array with enough space to store 'count' values.
+ final ArrayList<long[]> list = mParent.mLongs;
+ int whichArray = list.size()-1;
+ long[] array = list.get(whichArray);
+ if (mParent.mNextIndex + count > array.length) {
+ // if it won't fit then make a new array.
+ array = new long[ARRAY_SIZE];
+ list.add(array);
+ whichArray++;
+ mParent.mNextIndex = 0;
+ }
+
+ // The key is a combination of whichArray, which index in that array, and
+ // the table value itself, which will be used for lookup
+ final int key = (whichArray << ARRAY_SHIFT)
+ | (mParent.mNextIndex << INDEX_SHIFT)
+ | (((int)id) << ID_SHIFT);
+
+ mParent.mNextIndex += count;
+
+ // Store the key in the sparse lookup table for this Table object.
+ mTable = GrowingArrayUtils.insert(mTable != null ? mTable : EmptyArray.INT,
+ mSize, ~idx, key);
+ mSize++;
+
+ return key;
+ }
+ }
+
+ /**
+ * Looks up a key in the table.
+ *
+ * @return The key from this table or INVALID_KEY if the id is not found.
+ */
+ public int getKey(byte id) {
+ assertConsistency();
+
+ final int idx = binarySearch(id);
+ if (idx >= 0) {
+ return mTable[idx];
+ } else {
+ return INVALID_KEY;
+ }
+ }
+
+ /**
+ * Get the value for the given key and offset from that key.
+ *
+ * @param key A key as obtained from getKey or getOrAddKey.
+ * @param value The value to set.
+ */
+ public long getValue(int key) {
+ return getValue(key, 0);
+ }
+
+ /**
+ * Get the value for the given key and offset from that key.
+ *
+ * @param key A key as obtained from getKey or getOrAddKey.
+ * @param index The offset from that key. Must be less than the count
+ * provided to getOrAddKey when the space was allocated.
+ * @param value The value to set.
+ *
+ * @return the value, or 0 in case of an error
+ */
+ public long getValue(int key, int index) {
+ assertConsistency();
+
+ try {
+ final long[] array = mParent.mLongs.get(getArrayFromKey(key));
+ return array[getIndexFromKey(key) + index];
+ } catch (IndexOutOfBoundsException ex) {
+ logOrThrow("key=0x" + Integer.toHexString(key)
+ + " index=" + index + " -- " + dumpInternalState(), ex);
+ return 0;
+ }
+ }
+
+ /**
+ * Set the value for the given id at offset 0 from that id.
+ * If the id is not found, return 0 instead.
+ *
+ * @param id The id of the item.
+ */
+ public long getValueForId(byte id) {
+ return getValueForId(id, 0);
+ }
+
+ /**
+ * Set the value for the given id and index offset from that id.
+ * If the id is not found, return 0 instead.
+ *
+ * @param id The id of the item.
+ * @param index The offset from that key. Must be less than the count
+ * provided to getOrAddKey when the space was allocated.
+ */
+ public long getValueForId(byte id, int index) {
+ assertConsistency();
+
+ final int idx = binarySearch(id);
+ if (idx >= 0) {
+ final int key = mTable[idx];
+ try {
+ final long[] array = mParent.mLongs.get(getArrayFromKey(key));
+ return array[getIndexFromKey(key) + index];
+ } catch (IndexOutOfBoundsException ex) {
+ logOrThrow("id=0x" + Integer.toHexString(id) + " idx=" + idx
+ + " key=0x" + Integer.toHexString(key) + " index=" + index
+ + " -- " + dumpInternalState(), ex);
+ return 0;
+ }
+ } else {
+ return 0;
+ }
+ }
+
+ /**
+ * Return the raw storage long[] for the given key.
+ */
+ public long[] getArrayForKey(int key) {
+ assertConsistency();
+
+ return mParent.mLongs.get(getArrayFromKey(key));
+ }
+
+ /**
+ * Set the value for the given key and offset from that key.
+ *
+ * @param key A key as obtained from getKey or getOrAddKey.
+ * @param value The value to set.
+ */
+ public void setValue(int key, long value) {
+ setValue(key, 0, value);
+ }
+
+ /**
+ * Set the value for the given key and offset from that key.
+ *
+ * @param key A key as obtained from getKey or getOrAddKey.
+ * @param index The offset from that key. Must be less than the count
+ * provided to getOrAddKey when the space was allocated.
+ * @param value The value to set.
+ */
+ public void setValue(int key, int index, long value) {
+ assertConsistency();
+
+ if (value < 0) {
+ logOrThrow("can't store negative values"
+ + " key=0x" + Integer.toHexString(key)
+ + " index=" + index + " value=" + value
+ + " -- " + dumpInternalState());
+ return;
+ }
+
+ try {
+ final long[] array = mParent.mLongs.get(getArrayFromKey(key));
+ array[getIndexFromKey(key) + index] = value;
+ } catch (IndexOutOfBoundsException ex) {
+ logOrThrow("key=0x" + Integer.toHexString(key)
+ + " index=" + index + " value=" + value
+ + " -- " + dumpInternalState(), ex);
+ return;
+ }
+ }
+
+ /**
+ * Clear out the table, and reset the sequence numbers so future writes
+ * without allocations will assert.
+ */
+ public void resetTable() {
+ // Clear out our table.
+ mTable = null;
+ mSize = 0;
+
+ // Reset our sequence number. This will make all read/write calls
+ // start to fail, and then when we re-allocate it will be re-synced
+ // to that of mParent.
+ mSequence = UNINITIALIZED_SEQUENCE;
+ }
+
+ /**
+ * Write the keys stored in the table to the parcel. The parent must
+ * be separately written. Does not save the actual data.
+ */
+ public void writeToParcel(Parcel out) {
+ out.writeInt(mSequence);
+ out.writeInt(mSize);
+ for (int i=0; i<mSize; i++) {
+ out.writeInt(mTable[i]);
+ }
+ }
+
+ /**
+ * Read the keys from the parcel. The parent (with its long array) must
+ * have been previously initialized.
+ */
+ public boolean readFromParcel(Parcel in) {
+ // Read the state
+ mSequence = in.readInt();
+ mSize = in.readInt();
+ if (mSize != 0) {
+ mTable = new int[mSize];
+ for (int i=0; i<mSize; i++) {
+ mTable[i] = in.readInt();
+ }
+ } else {
+ mTable = null;
+ }
+
+ // Make sure we're all healthy
+ if (validateKeys(true)) {
+ return true;
+ } else {
+ // Clear it out
+ mSize = 0;
+ mTable = null;
+ return false;
+ }
+ }
+
+ /**
+ * Return the number of keys that have been added to this Table.
+ */
+ public int getKeyCount() {
+ return mSize;
+ }
+
+ /**
+ * Get the key at the given index in our table.
+ */
+ public int getKeyAt(int i) {
+ return mTable[i];
+ }
+
+ /**
+ * Throw an exception if one of a variety of internal consistency checks fails.
+ */
+ private void assertConsistency() {
+ // Assert that our sequewnce number has been initialized. If it hasn't
+ // that means someone tried to read or write data without allocating it
+ // since we were created or reset.
+ if (mSequence == UNINITIALIZED_SEQUENCE) {
+ logOrThrow("mSequence == UNINITIALIZED_SEQUENCE in"
+ + " SparseMappingTable.Table. mParent.mSequence=" + mParent.mSequence);
+ }
+
+ // Assert that our sequence number matches mParent's. If it isn't that means
+ // we have been reset and our
+ if (mSequence != mParent.mSequence) {
+ if (mSequence < mParent.mSequence) {
+ logOrThrow("Sequence mismatch. SparseMappingTable.resetTable()"
+ + " called but not Table.resetTable() -- "
+ + dumpInternalState());
+ } else if (mSequence > mParent.mSequence) {
+ logOrThrow("Sequence mismatch. Table.resetTable()"
+ + " called but not SparseMappingTable.resetTable() -- "
+ + dumpInternalState());
+ }
+ }
+ }
+
+ /**
+ * Finds the 'id' inside the array of length size (physical size of the array
+ * is not used).
+ *
+ * @return The index of the array, or the bitwise not (~index) of where it
+ * would go if you wanted to insert 'id' into the array.
+ */
+ private int binarySearch(byte id) {
+ int lo = 0;
+ int hi = mSize - 1;
+
+ while (lo <= hi) {
+ int mid = (lo + hi) >>> 1;
+ byte midId = (byte)((mTable[mid] >> ID_SHIFT) & ID_MASK);
+
+ if (midId < id) {
+ lo = mid + 1;
+ } else if (midId > id) {
+ hi = mid - 1;
+ } else {
+ return mid; // id found
+ }
+ }
+ return ~lo; // id not present
+ }
+
+ /**
+ * Check that all the keys are valid locations in the long arrays.
+ *
+ * If any aren't, log it and return false. Else return true.
+ */
+ private boolean validateKeys(boolean log) {
+ ArrayList<long[]> longs = mParent.mLongs;
+ final int longsSize = longs.size();
+
+ final int N = mSize;
+ for (int i=0; i<N; i++) {
+ final int key = mTable[i];
+ final int arrayIndex = getArrayFromKey(key);
+ final int index = getIndexFromKey(key);
+ if (arrayIndex >= longsSize || index >= longs.get(arrayIndex).length) {
+ if (log) {
+ Slog.w(TAG, "Invalid stats at index " + i + " -- " + dumpInternalState());
+ }
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ public String dumpInternalState() {
+ StringBuilder sb = new StringBuilder();
+ sb.append("SparseMappingTable.Table{mSequence=");
+ sb.append(mSequence);
+ sb.append(" mParent.mSequence=");
+ sb.append(mParent.mSequence);
+ sb.append(" mParent.mLongs.size()=");
+ sb.append(mParent.mLongs.size());
+ sb.append(" mSize=");
+ sb.append(mSize);
+ sb.append(" mTable=");
+ if (mTable == null) {
+ sb.append("null");
+ } else {
+ final int N = mTable.length;
+ sb.append('[');
+ for (int i=0; i<N; i++) {
+ final int key = mTable[i];
+ sb.append("0x");
+ sb.append(Integer.toHexString((key >> ID_SHIFT) & ID_MASK));
+ sb.append("/0x");
+ sb.append(Integer.toHexString((key >> ARRAY_SHIFT) & ARRAY_MASK));
+ sb.append("/0x");
+ sb.append(Integer.toHexString((key >> INDEX_SHIFT) & INDEX_MASK));
+ if (i != N-1) {
+ sb.append(", ");
+ }
+ }
+ sb.append(']');
+ }
+ sb.append(" clazz=");
+ sb.append(getClass().getName());
+ sb.append('}');
+
+ return sb.toString();
+ }
+ }
+
+ /**
+ * Wipe out all the data.
+ */
+ public void reset() {
+ // Clear out mLongs, and prime it with a new array of data
+ mLongs.clear();
+ mLongs.add(new long[ARRAY_SIZE]);
+ mNextIndex = 0;
+
+ // Increment out sequence counter, because all of the tables will
+ // now be out of sync with the data.
+ mSequence++;
+ }
+
+ /**
+ * Write the data arrays to the parcel.
+ */
+ public void writeToParcel(Parcel out) {
+ out.writeInt(mSequence);
+ out.writeInt(mNextIndex);
+ final int N = mLongs.size();
+ out.writeInt(N);
+ for (int i=0; i<N-1; i++) {
+ final long[] array = mLongs.get(i);
+ out.writeInt(array.length);
+ writeCompactedLongArray(out, array, array.length);
+ }
+ // save less for the last one. upon re-loading they'll just start a new array.
+ final long[] lastLongs = mLongs.get(N-1);
+ out.writeInt(mNextIndex);
+ writeCompactedLongArray(out, lastLongs, mNextIndex);
+ }
+
+ /**
+ * Read the data arrays from the parcel.
+ */
+ public void readFromParcel(Parcel in) {
+ mSequence = in.readInt();
+ mNextIndex = in.readInt();
+
+ mLongs.clear();
+ final int N = in.readInt();
+ for (int i=0; i<N; i++) {
+ final int size = in.readInt();
+ final long[] array = new long[size];
+ readCompactedLongArray(in, array, size);
+ mLongs.add(array);
+ }
+ }
+
+ /**
+ * Write the long array to the parcel in a compacted form. Does not allow negative
+ * values in the array.
+ */
+ private static void writeCompactedLongArray(Parcel out, long[] array, int num) {
+ for (int i=0; i<num; i++) {
+ long val = array[i];
+ if (val < 0) {
+ Slog.w(TAG, "Time val negative: " + val);
+ val = 0;
+ }
+ if (val <= Integer.MAX_VALUE) {
+ out.writeInt((int)val);
+ } else {
+ int top = ~((int)((val>>32)&0x7fffffff));
+ int bottom = (int)(val&0xfffffff);
+ out.writeInt(top);
+ out.writeInt(bottom);
+ }
+ }
+ }
+
+ /**
+ * Read the compacted array into the long[].
+ */
+ private static void readCompactedLongArray(Parcel in, long[] array, int num) {
+ final int alen = array.length;
+ if (num > alen) {
+ logOrThrow("bad array lengths: got " + num + " array is " + alen);
+ return;
+ }
+ int i;
+ for (i=0; i<num; i++) {
+ int val = in.readInt();
+ if (val >= 0) {
+ array[i] = val;
+ } else {
+ int bottom = in.readInt();
+ array[i] = (((long)~val)<<32) | bottom;
+ }
+ }
+ while (i < alen) {
+ array[i] = 0;
+ i++;
+ }
+ }
+
+ /**
+ * Extract the id from a key.
+ */
+ public static byte getIdFromKey(int key) {
+ return (byte)((key >> ID_SHIFT) & ID_MASK);
+ }
+
+ /**
+ * Gets the index of the array in the list of arrays.
+ *
+ * Not to be confused with getIndexFromKey.
+ */
+ public static int getArrayFromKey(int key) {
+ return (key >> ARRAY_SHIFT) & ARRAY_MASK;
+ }
+
+ /**
+ * Gets the index of a value in a long[].
+ *
+ * Not to be confused with getArrayFromKey.
+ */
+ public static int getIndexFromKey(int key) {
+ return (key >> INDEX_SHIFT) & INDEX_MASK;
+ }
+
+ /**
+ * Do a Slog.wtf or throw an exception (thereby crashing the system process if
+ * this is a debug build.)
+ */
+ private static void logOrThrow(String message) {
+ logOrThrow(message, null);
+ }
+
+ /**
+ * Do a Slog.wtf or throw an exception (thereby crashing the system process if
+ * this is an eng build.)
+ */
+ private static void logOrThrow(String message, Throwable th) {
+ Slog.wtf(TAG, message, th);
+ if (Build.TYPE.equals("eng")) {
+ throw new RuntimeException(message, th);
+ }
+ }
+}
diff --git a/core/java/com/android/internal/app/procstats/SysMemUsageTable.java b/core/java/com/android/internal/app/procstats/SysMemUsageTable.java
new file mode 100644
index 0000000..e71bc55
--- /dev/null
+++ b/core/java/com/android/internal/app/procstats/SysMemUsageTable.java
@@ -0,0 +1,189 @@
+/*
+ * Copyright (C) 2013 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.app.procstats;
+
+import android.util.DebugUtils;
+
+import static com.android.internal.app.procstats.ProcessStats.STATE_COUNT;
+import static com.android.internal.app.procstats.ProcessStats.STATE_NOTHING;
+import static com.android.internal.app.procstats.ProcessStats.SYS_MEM_USAGE_SAMPLE_COUNT;
+import static com.android.internal.app.procstats.ProcessStats.SYS_MEM_USAGE_CACHED_MINIMUM;
+import static com.android.internal.app.procstats.ProcessStats.SYS_MEM_USAGE_CACHED_AVERAGE;
+import static com.android.internal.app.procstats.ProcessStats.SYS_MEM_USAGE_CACHED_MAXIMUM;
+import static com.android.internal.app.procstats.ProcessStats.SYS_MEM_USAGE_FREE_MINIMUM;
+import static com.android.internal.app.procstats.ProcessStats.SYS_MEM_USAGE_FREE_AVERAGE;
+import static com.android.internal.app.procstats.ProcessStats.SYS_MEM_USAGE_FREE_MAXIMUM;
+import static com.android.internal.app.procstats.ProcessStats.SYS_MEM_USAGE_ZRAM_MINIMUM;
+import static com.android.internal.app.procstats.ProcessStats.SYS_MEM_USAGE_ZRAM_AVERAGE;
+import static com.android.internal.app.procstats.ProcessStats.SYS_MEM_USAGE_ZRAM_MAXIMUM;
+import static com.android.internal.app.procstats.ProcessStats.SYS_MEM_USAGE_KERNEL_MINIMUM;
+import static com.android.internal.app.procstats.ProcessStats.SYS_MEM_USAGE_KERNEL_AVERAGE;
+import static com.android.internal.app.procstats.ProcessStats.SYS_MEM_USAGE_KERNEL_MAXIMUM;
+import static com.android.internal.app.procstats.ProcessStats.SYS_MEM_USAGE_NATIVE_MINIMUM;
+import static com.android.internal.app.procstats.ProcessStats.SYS_MEM_USAGE_NATIVE_AVERAGE;
+import static com.android.internal.app.procstats.ProcessStats.SYS_MEM_USAGE_NATIVE_MAXIMUM;
+import static com.android.internal.app.procstats.ProcessStats.SYS_MEM_USAGE_COUNT;
+
+import java.io.PrintWriter;
+
+
+/**
+ * Class to accumulate system mem usage data.
+ */
+public class SysMemUsageTable extends SparseMappingTable.Table {
+ /**
+ * Construct the SysMemUsageTable with 'tableData' as backing store
+ * for the longs data.
+ */
+ public SysMemUsageTable(SparseMappingTable tableData) {
+ super(tableData);
+ }
+
+ /**
+ * Merge the stats given into our own values.
+ *
+ * @param that SysMemUsageTable to copy from.
+ */
+ public void mergeStats(SysMemUsageTable that) {
+ final int N = that.getKeyCount();
+ for (int i=0; i<N; i++) {
+ final int key = that.getKeyAt(i);
+
+ final int state = SparseMappingTable.getIdFromKey(key);
+ final long[] addData = that.getArrayForKey(key);
+ final int addOff = SparseMappingTable.getIndexFromKey(key);
+
+ mergeStats(state, addData, addOff);
+ }
+ }
+
+ /**
+ * Merge the stats given into our own values.
+ *
+ * @param state The state
+ * @param addData The data array to copy
+ * @param addOff The index in addOff to start copying from
+ */
+ public void mergeStats(int state, long[] addData, int addOff) {
+ final int key = getOrAddKey((byte)state, SYS_MEM_USAGE_COUNT);
+
+ final long[] dstData = getArrayForKey(key);
+ final int dstOff = SparseMappingTable.getIndexFromKey(key);
+
+ SysMemUsageTable.mergeSysMemUsage(dstData, dstOff, addData, addOff);
+ }
+
+ /**
+ * Return a long[] containing the merge of all of the usage in this table.
+ */
+ public long[] getTotalMemUsage() {
+ long[] total = new long[SYS_MEM_USAGE_COUNT];
+ final int N = getKeyCount();
+ for (int i=0; i<N; i++) {
+ final int key = getKeyAt(i);
+
+ final long[] addData = getArrayForKey(key);
+ final int addOff = SparseMappingTable.getIndexFromKey(key);
+
+ SysMemUsageTable.mergeSysMemUsage(total, 0, addData, addOff);
+ }
+ return total;
+ }
+
+ /**
+ * Merge the stats from one raw long[] into another.
+ *
+ * @param dstData The destination array
+ * @param dstOff The index in the destination array to start from
+ * @param addData The source array
+ * @param addOff The index in the source array to start from
+ */
+ public static void mergeSysMemUsage(long[] dstData, int dstOff,
+ long[] addData, int addOff) {
+ final long dstCount = dstData[dstOff+SYS_MEM_USAGE_SAMPLE_COUNT];
+ final long addCount = addData[addOff+SYS_MEM_USAGE_SAMPLE_COUNT];
+ if (dstCount == 0) {
+ dstData[dstOff+SYS_MEM_USAGE_SAMPLE_COUNT] = addCount;
+ for (int i=SYS_MEM_USAGE_CACHED_MINIMUM; i<SYS_MEM_USAGE_COUNT; i++) {
+ dstData[dstOff+i] = addData[addOff+i];
+ }
+ } else if (addCount > 0) {
+ dstData[dstOff+SYS_MEM_USAGE_SAMPLE_COUNT] = dstCount + addCount;
+ for (int i=SYS_MEM_USAGE_CACHED_MINIMUM; i<SYS_MEM_USAGE_COUNT; i+=3) {
+ if (dstData[dstOff+i] > addData[addOff+i]) {
+ dstData[dstOff+i] = addData[addOff+i];
+ }
+ dstData[dstOff+i+1] = (long)(
+ ((dstData[dstOff+i+1]*(double)dstCount)
+ + (addData[addOff+i+1]*(double)addCount))
+ / (dstCount+addCount) );
+ if (dstData[dstOff+i+2] < addData[addOff+i+2]) {
+ dstData[dstOff+i+2] = addData[addOff+i+2];
+ }
+ }
+ }
+ }
+
+
+ public void dump(PrintWriter pw, String prefix, int[] screenStates, int[] memStates) {
+ int printedScreen = -1;
+ for (int is=0; is<screenStates.length; is++) {
+ int printedMem = -1;
+ for (int im=0; im<memStates.length; im++) {
+ final int iscreen = screenStates[is];
+ final int imem = memStates[im];
+ final int bucket = ((iscreen + imem) * STATE_COUNT);
+ long count = getValueForId((byte)bucket, SYS_MEM_USAGE_SAMPLE_COUNT);
+ if (count > 0) {
+ pw.print(prefix);
+ if (screenStates.length > 1) {
+ DumpUtils.printScreenLabel(pw, printedScreen != iscreen
+ ? iscreen : STATE_NOTHING);
+ printedScreen = iscreen;
+ }
+ if (memStates.length > 1) {
+ DumpUtils.printMemLabel(pw,
+ printedMem != imem ? imem : STATE_NOTHING, '\0');
+ printedMem = imem;
+ }
+ pw.print(": ");
+ pw.print(count);
+ pw.println(" samples:");
+ dumpCategory(pw, prefix, " Cached", bucket, SYS_MEM_USAGE_CACHED_MINIMUM);
+ dumpCategory(pw, prefix, " Free", bucket, SYS_MEM_USAGE_FREE_MINIMUM);
+ dumpCategory(pw, prefix, " ZRam", bucket, SYS_MEM_USAGE_ZRAM_MINIMUM);
+ dumpCategory(pw, prefix, " Kernel", bucket, SYS_MEM_USAGE_KERNEL_MINIMUM);
+ dumpCategory(pw, prefix, " Native", bucket, SYS_MEM_USAGE_NATIVE_MINIMUM);
+ }
+ }
+ }
+ }
+
+ private void dumpCategory(PrintWriter pw, String prefix, String label, int bucket, int index) {
+ pw.print(prefix); pw.print(label);
+ pw.print(": ");
+ DebugUtils.printSizeValue(pw, getValueForId((byte)bucket, index) * 1024);
+ pw.print(" min, ");
+ DebugUtils.printSizeValue(pw, getValueForId((byte)bucket, index + 1) * 1024);
+ pw.print(" avg, ");
+ DebugUtils.printSizeValue(pw, getValueForId((byte)bucket, index+2) * 1024);
+ pw.println(" max");
+ }
+
+}
+
+
diff --git a/core/java/com/android/internal/app/procstats/package.html b/core/java/com/android/internal/app/procstats/package.html
new file mode 100644
index 0000000..db6f78b
--- /dev/null
+++ b/core/java/com/android/internal/app/procstats/package.html
@@ -0,0 +1,3 @@
+<body>
+{@hide}
+</body>
\ No newline at end of file
diff --git a/core/java/com/android/internal/backup/LocalTransport.java b/core/java/com/android/internal/backup/LocalTransport.java
index 10027b6..5e8f4a2 100644
--- a/core/java/com/android/internal/backup/LocalTransport.java
+++ b/core/java/com/android/internal/backup/LocalTransport.java
@@ -27,7 +27,6 @@
import android.content.pm.PackageInfo;
import android.os.Environment;
import android.os.ParcelFileDescriptor;
-import android.os.SELinux;
import android.system.ErrnoException;
import android.system.Os;
import android.system.StructStat;
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index b0ef012..bbefcb5 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -4012,6 +4012,7 @@
if (DEBUG_HISTORY) Slog.v(TAG, "BLE scan started for: "
+ Integer.toHexString(mHistoryCur.states2));
addHistoryRecordLocked(elapsedRealtime, uptime);
+ mBluetoothScanTimer.startRunningLocked(elapsedRealtime);
}
mBluetoothScanNesting++;
getUidStatsLocked(uid).noteBluetoothScanStartedLocked(elapsedRealtime);
@@ -4034,6 +4035,7 @@
if (DEBUG_HISTORY) Slog.v(TAG, "BLE scan stopped for: "
+ Integer.toHexString(mHistoryCur.states2));
addHistoryRecordLocked(elapsedRealtime, uptime);
+ mBluetoothScanTimer.stopRunningLocked(elapsedRealtime);
}
getUidStatsLocked(uid).noteBluetoothScanStoppedLocked(elapsedRealtime);
}
diff --git a/core/java/com/android/internal/os/PowerProfile.java b/core/java/com/android/internal/os/PowerProfile.java
index 14ebe22..79138b7 100644
--- a/core/java/com/android/internal/os/PowerProfile.java
+++ b/core/java/com/android/internal/os/PowerProfile.java
@@ -85,6 +85,7 @@
public static final String POWER_WIFI_CONTROLLER_IDLE = "wifi.controller.idle";
public static final String POWER_WIFI_CONTROLLER_RX = "wifi.controller.rx";
public static final String POWER_WIFI_CONTROLLER_TX = "wifi.controller.tx";
+ public static final String POWER_WIFI_CONTROLLER_TX_LEVELS = "wifi.controller.tx_levels";
public static final String POWER_WIFI_CONTROLLER_OPERATING_VOLTAGE = "wifi.controller.voltage";
public static final String POWER_BLUETOOTH_CONTROLLER_IDLE = "bluetooth.controller.idle";
@@ -287,9 +288,15 @@
};
for (int i = 0; i < configResIds.length; i++) {
+ String key = configResIdKeys[i];
+ // if we already have some of these parameters in power_profile.xml, ignore the
+ // value in config.xml
+ if ((sPowerMap.containsKey(key) && (Double) sPowerMap.get(key) > 0)) {
+ continue;
+ }
int value = resources.getInteger(configResIds[i]);
if (value > 0) {
- sPowerMap.put(configResIdKeys[i], (double) value);
+ sPowerMap.put(key, (double) value);
}
}
}
diff --git a/core/java/com/android/internal/policy/DecorView.java b/core/java/com/android/internal/policy/DecorView.java
index 9904893..ea0fbda 100644
--- a/core/java/com/android/internal/policy/DecorView.java
+++ b/core/java/com/android/internal/policy/DecorView.java
@@ -183,6 +183,7 @@
private boolean mLastHasBottomStableInset = false;
private boolean mLastHasRightStableInset = false;
private int mLastWindowFlags = 0;
+ private boolean mLastShouldAlwaysConsumeNavBar = false;
private int mRootScrollY = 0;
@@ -208,6 +209,7 @@
private Drawable mResizingBackgroundDrawable;
private Drawable mCaptionBackgroundDrawable;
private Drawable mUserCaptionBackgroundDrawable;
+ private Drawable mOriginalBackgroundDrawable;
private float mAvailableWidth;
@@ -887,6 +889,11 @@
mBackgroundPadding.setEmpty();
}
drawableChanged();
+
+ // Make sure we don't reset to the old drawable when finishing resizing.
+ if (mResizeMode != RESIZE_MODE_INVALID) {
+ mOriginalBackgroundDrawable = null;
+ }
}
}
@@ -996,6 +1003,7 @@
boolean hasRightStableInset = insets.getStableInsetRight() != 0;
disallowAnimate |= (hasRightStableInset != mLastHasRightStableInset);
mLastHasRightStableInset = hasRightStableInset;
+ mLastShouldAlwaysConsumeNavBar = insets.shouldAlwaysConsumeNavBar();
}
boolean navBarToRightEdge = isNavBarToRightEdge(mLastBottomInset, mLastRightInset);
@@ -1016,12 +1024,11 @@
// When we expand the window with FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS, we still need
// to ensure that the rest of the view hierarchy doesn't notice it, unless they've
// explicitly asked for it.
-
boolean consumingNavBar =
(attrs.flags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0
&& (sysUiVisibility & SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) == 0
&& (sysUiVisibility & SYSTEM_UI_FLAG_HIDE_NAVIGATION) == 0
- || (insets != null && insets.shouldAlwaysConsumeNavBar());
+ || mLastShouldAlwaysConsumeNavBar;
// If we didn't request fullscreen layout, but we still got it because of the
// mForceWindowDrawsStatusBarBackground flag, also consume top inset.
@@ -1949,6 +1956,9 @@
updateElevation();
updateColorViews(null /* insets */, false);
+
+ mOriginalBackgroundDrawable = getBackground();
+ setBackgroundDrawable(null);
}
mResizeMode = resizeMode;
getViewRootImpl().requestInvalidateRootRenderNode();
@@ -1960,6 +1970,10 @@
updateColorViews(null /* insets */, false);
mResizeMode = RESIZE_MODE_INVALID;
getViewRootImpl().requestInvalidateRootRenderNode();
+ if (mOriginalBackgroundDrawable != null) {
+ setBackgroundDrawable(mOriginalBackgroundDrawable);
+ mOriginalBackgroundDrawable = null;
+ }
}
@Override
diff --git a/core/java/com/android/internal/policy/PhoneWindow.java b/core/java/com/android/internal/policy/PhoneWindow.java
index 794a6d6..0f257d7 100644
--- a/core/java/com/android/internal/policy/PhoneWindow.java
+++ b/core/java/com/android/internal/policy/PhoneWindow.java
@@ -24,6 +24,7 @@
import android.app.SearchManager;
import android.os.UserHandle;
+import android.text.TextUtils;
import android.view.ContextThemeWrapper;
import android.view.Gravity;
import android.view.IRotationWatcher.Stub;
@@ -514,6 +515,11 @@
mDecorContentParent.setWindowTitle(title);
}
mTitle = title;
+ WindowManager.LayoutParams params = getAttributes();
+ if (!TextUtils.equals(title, params.getTitle())) {
+ params.setTitle(title);
+ dispatchWindowAttributesChanged(getAttributes());
+ }
}
@Override
@@ -680,7 +686,7 @@
}
@Override
- public void onMultiWindowChanged() {
+ public void onMultiWindowModeChanged() {
if (mDecor != null) {
mDecor.onConfigurationChanged(getContext().getResources().getConfiguration());
}
diff --git a/core/java/com/android/internal/util/ArrayUtils.java b/core/java/com/android/internal/util/ArrayUtils.java
index ee73b90..bed5a2e 100644
--- a/core/java/com/android/internal/util/ArrayUtils.java
+++ b/core/java/com/android/internal/util/ArrayUtils.java
@@ -238,6 +238,14 @@
return total;
}
+ public static int[] convertToIntArray(List<Integer> list) {
+ int[] array = new int[list.size()];
+ for (int i = 0; i < list.size(); i++) {
+ array[i] = list.get(i);
+ }
+ return array;
+ }
+
/**
* Adds value to given array if not already present, providing set-like
* behavior.
diff --git a/core/java/com/android/internal/util/AsyncChannel.java b/core/java/com/android/internal/util/AsyncChannel.java
index bd0e6ce..d8be9fd 100644
--- a/core/java/com/android/internal/util/AsyncChannel.java
+++ b/core/java/com/android/internal/util/AsyncChannel.java
@@ -402,7 +402,7 @@
// Initialize destination fields
mDstMessenger = dstMessenger;
-
+ linkToDeathMonitor();
if (DBG) log("connected srcHandler to the dstMessenger X");
}
@@ -844,22 +844,30 @@
msg.arg1 = status;
msg.obj = this;
msg.replyTo = mDstMessenger;
+ if (!linkToDeathMonitor()) {
+ // Override status to indicate failure
+ msg.arg1 = STATUS_BINDING_UNSUCCESSFUL;
+ }
- /*
- * Link to death only when bindService isn't used.
- */
- if (mConnection == null) {
+ mSrcHandler.sendMessage(msg);
+ }
+
+ /**
+ * Link to death monitor for destination messenger. Returns true if successfully binded to
+ * destination messenger; false otherwise.
+ */
+ private boolean linkToDeathMonitor() {
+ // Link to death only when bindService isn't used and not already linked.
+ if (mConnection == null && mDeathMonitor == null) {
mDeathMonitor = new DeathMonitor();
try {
mDstMessenger.getBinder().linkToDeath(mDeathMonitor, 0);
} catch (RemoteException e) {
mDeathMonitor = null;
- // Override status to indicate failure
- msg.arg1 = STATUS_BINDING_UNSUCCESSFUL;
+ return false;
}
}
-
- mSrcHandler.sendMessage(msg);
+ return true;
}
/**
diff --git a/core/java/com/android/internal/util/Preconditions.java b/core/java/com/android/internal/util/Preconditions.java
index c46851e..1ead5b3 100644
--- a/core/java/com/android/internal/util/Preconditions.java
+++ b/core/java/com/android/internal/util/Preconditions.java
@@ -56,7 +56,7 @@
* @return the string reference that was validated
* @throws IllegalArgumentException if {@code string} is empty
*/
- public static @NonNull String checkStringNotEmpty(final String string) {
+ public static @NonNull <T extends CharSequence> T checkStringNotEmpty(final T string) {
if (TextUtils.isEmpty(string)) {
throw new IllegalArgumentException();
}
@@ -73,7 +73,7 @@
* @return the string reference that was validated
* @throws IllegalArgumentException if {@code string} is empty
*/
- public static @NonNull String checkStringNotEmpty(final String string,
+ public static @NonNull <T extends CharSequence> T checkStringNotEmpty(final T string,
final Object errorMessage) {
if (TextUtils.isEmpty(string)) {
throw new IllegalArgumentException(String.valueOf(errorMessage));
@@ -141,13 +141,17 @@
/**
* Check the requested flags, throwing if any requested flags are outside
* the allowed set.
+ *
+ * @return the validated requested flags.
*/
- public static void checkFlagsArgument(final int requestedFlags, final int allowedFlags) {
+ public static int checkFlagsArgument(final int requestedFlags, final int allowedFlags) {
if ((requestedFlags & allowedFlags) != requestedFlags) {
throw new IllegalArgumentException("Requested flags 0x"
+ Integer.toHexString(requestedFlags) + ", but only 0x"
+ Integer.toHexString(allowedFlags) + " are allowed");
}
+
+ return requestedFlags;
}
/**
@@ -170,6 +174,37 @@
/**
* Ensures that that the argument numeric value is non-negative.
*
+ * @param value a numeric int value
+ *
+ * @return the validated numeric value
+ * @throws IllegalArgumentException if {@code value} was negative
+ */
+ public static @IntRange(from = 0) int checkArgumentNonnegative(final int value) {
+ if (value < 0) {
+ throw new IllegalArgumentException();
+ }
+
+ return value;
+ }
+
+ /**
+ * Ensures that that the argument numeric value is non-negative.
+ *
+ * @param value a numeric long value
+ * @return the validated numeric value
+ * @throws IllegalArgumentException if {@code value} was negative
+ */
+ public static long checkArgumentNonnegative(final long value) {
+ if (value < 0) {
+ throw new IllegalArgumentException();
+ }
+
+ return value;
+ }
+
+ /**
+ * Ensures that that the argument numeric value is non-negative.
+ *
* @param value a numeric long value
* @param errorMessage the exception message to use if the check fails
* @return the validated numeric value
diff --git a/core/java/com/android/internal/view/IInputConnectionWrapper.java b/core/java/com/android/internal/view/IInputConnectionWrapper.java
index 6c1ebb4..3a4afad 100644
--- a/core/java/com/android/internal/view/IInputConnectionWrapper.java
+++ b/core/java/com/android/internal/view/IInputConnectionWrapper.java
@@ -27,13 +27,12 @@
import android.os.RemoteException;
import android.util.Log;
import android.view.KeyEvent;
-import android.view.inputmethod.BaseInputConnection;
import android.view.inputmethod.CompletionInfo;
import android.view.inputmethod.CorrectionInfo;
import android.view.inputmethod.ExtractedTextRequest;
import android.view.inputmethod.InputConnection;
-
-import java.lang.ref.WeakReference;
+import android.view.inputmethod.InputConnectionInspector;
+import android.view.inputmethod.InputConnectionInspector.MissingMethodFlags;
public abstract class IInputConnectionWrapper extends IInputContext.Stub {
static final String TAG = "IInputConnectionWrapper";
@@ -61,7 +60,7 @@
private static final int DO_PERFORM_PRIVATE_COMMAND = 120;
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_REPORT_FINISH = 150;
+ private static final int DO_CLOSE_CONNECTION = 150;
@GuardedBy("mLock")
@Nullable
@@ -222,8 +221,8 @@
seq, callback));
}
- public void reportFinish() {
- dispatchMessage(obtainMessage(DO_REPORT_FINISH));
+ public void closeConnection() {
+ dispatchMessage(obtainMessage(DO_CLOSE_CONNECTION));
}
void dispatchMessage(Message msg) {
@@ -501,10 +500,10 @@
}
return;
}
- case DO_REPORT_FINISH: {
+ case DO_CLOSE_CONNECTION: {
// Note that we do not need to worry about race condition here, because 1) mFinished
// is updated only inside this block, and 2) the code here is running on a Handler
- // hence we assume multiple DO_REPORT_FINISH messages will not be handled at the
+ // hence we assume multiple DO_CLOSE_CONNECTION messages will not be handled at the
// same time.
if (isFinished()) {
return;
@@ -518,11 +517,10 @@
if (ic == null) {
return;
}
- ic.finishComposingText();
- // TODO: Make reportFinish() public method of InputConnection to remove this
- // check.
- if (ic instanceof BaseInputConnection) {
- ((BaseInputConnection) ic).reportFinish();
+ @MissingMethodFlags
+ final int missingMethods = InputConnectionInspector.getMissingMethodFlags(ic);
+ if ((missingMethods & MissingMethodFlags.CLOSE_CONNECTION) == 0) {
+ ic.closeConnection();
}
} finally {
synchronized (mLock) {
diff --git a/core/java/com/android/internal/view/InputConnectionWrapper.java b/core/java/com/android/internal/view/InputConnectionWrapper.java
index 85b8606..f9884d8 100644
--- a/core/java/com/android/internal/view/InputConnectionWrapper.java
+++ b/core/java/com/android/internal/view/InputConnectionWrapper.java
@@ -487,6 +487,10 @@
return null;
}
+ public void closeConnection() {
+ // Nothing should happen when called from input method.
+ }
+
private boolean isMethodMissing(@MissingMethodFlags final int methodFlag) {
return (mMissingMethods & methodFlag) == methodFlag;
}
diff --git a/core/java/com/android/internal/view/animation/FallbackLUTInterpolator.java b/core/java/com/android/internal/view/animation/FallbackLUTInterpolator.java
index 526e2ae..9e2cbdb 100644
--- a/core/java/com/android/internal/view/animation/FallbackLUTInterpolator.java
+++ b/core/java/com/android/internal/view/animation/FallbackLUTInterpolator.java
@@ -45,7 +45,8 @@
private static float[] createLUT(TimeInterpolator interpolator, long duration) {
long frameIntervalNanos = Choreographer.getInstance().getFrameIntervalNanos();
int animIntervalMs = (int) (frameIntervalNanos / TimeUtils.NANOS_PER_MS);
- int numAnimFrames = (int) Math.ceil(((double) duration) / animIntervalMs);
+ // We need 2 frame values as the minimal.
+ int numAnimFrames = Math.max(2, (int) Math.ceil(((double) duration) / animIntervalMs));
float values[] = new float[numAnimFrames];
float lastFrame = numAnimFrames - 1;
for (int i = 0; i < numAnimFrames; i++) {
diff --git a/core/java/com/android/internal/view/menu/ActionMenuItemView.java b/core/java/com/android/internal/view/menu/ActionMenuItemView.java
index bd97e5d..4738f5e 100644
--- a/core/java/com/android/internal/view/menu/ActionMenuItemView.java
+++ b/core/java/com/android/internal/view/menu/ActionMenuItemView.java
@@ -346,16 +346,6 @@
}
return false;
}
-
- @Override
- protected boolean onForwardingStopped() {
- final ShowableListMenu popup = getPopup();
- if (popup != null) {
- popup.dismiss();
- return true;
- }
- return false;
- }
}
public static abstract class PopupCallback {
diff --git a/core/java/com/android/internal/view/menu/MenuBuilder.java b/core/java/com/android/internal/view/menu/MenuBuilder.java
index 31b2f96..df57639 100644
--- a/core/java/com/android/internal/view/menu/MenuBuilder.java
+++ b/core/java/com/android/internal/view/menu/MenuBuilder.java
@@ -65,7 +65,6 @@
private final Context mContext;
private final Resources mResources;
- private final boolean mShowCascadingMenus;
/**
* Whether the shortcuts should be qwerty-accessible. Use isQwertyMode()
@@ -188,9 +187,6 @@
public MenuBuilder(Context context) {
mContext = context;
mResources = context.getResources();
- mShowCascadingMenus = context.getResources().getBoolean(
- com.android.internal.R.bool.config_enableCascadingSubmenus);
-
mItems = new ArrayList<MenuItemImpl>();
mVisibleItems = new ArrayList<MenuItemImpl>();
@@ -915,10 +911,6 @@
close(true /* closeAllMenus */);
}
} else if (itemImpl.hasSubMenu() || providerHasSubMenu) {
- if (!mShowCascadingMenus) {
- close(false /* closeAllMenus */);
- }
-
if (!itemImpl.hasSubMenu()) {
itemImpl.setSubMenu(new SubMenuBuilder(getContext(), this, itemImpl));
}
diff --git a/core/java/com/android/internal/view/menu/StandardMenuPopup.java b/core/java/com/android/internal/view/menu/StandardMenuPopup.java
index 2cb224e..8ced36f 100644
--- a/core/java/com/android/internal/view/menu/StandardMenuPopup.java
+++ b/core/java/com/android/internal/view/menu/StandardMenuPopup.java
@@ -240,7 +240,10 @@
mTreeObserver = null;
}
mShownAnchorView.removeOnAttachStateChangeListener(mAttachStateChangeListener);
- mOnDismissListener.onDismiss();
+
+ if (mOnDismissListener != null) {
+ mOnDismissListener.onDismiss();
+ }
}
@Override
@@ -265,6 +268,13 @@
subPopup.setPresenterCallback(mPresenterCallback);
subPopup.setForceShowIcon(mAdapter.getForceShowIcon());
+ // Pass responsibility for handling onDismiss to the submenu.
+ subPopup.setOnDismissListener(mOnDismissListener);
+ mOnDismissListener = null;
+
+ // Close this menu popup to make room for the submenu popup.
+ dismiss();
+
// Show the new sub-menu popup at the same location as this popup.
if (subPopup.tryShow(mXOffset, mYOffset)) {
if (mPresenterCallback != null) {
diff --git a/core/java/com/android/internal/widget/DecorCaptionView.java b/core/java/com/android/internal/widget/DecorCaptionView.java
index 409a17f..e59d7ba 100644
--- a/core/java/com/android/internal/widget/DecorCaptionView.java
+++ b/core/java/com/android/internal/widget/DecorCaptionView.java
@@ -136,7 +136,7 @@
public void setPhoneWindow(PhoneWindow owner, boolean show) {
mOwner = owner;
mShow = show;
- mOverlayWithAppContent = owner.getOverlayDecorCaption();
+ mOverlayWithAppContent = owner.isOverlayWithDecorCaptionEnabled();
if (mOverlayWithAppContent) {
// The caption is covering the content, so we make its background transparent to make
// the content visible.
diff --git a/core/java/com/android/internal/widget/EditableInputConnection.java b/core/java/com/android/internal/widget/EditableInputConnection.java
index a96b5a0..7f7528d 100644
--- a/core/java/com/android/internal/widget/EditableInputConnection.java
+++ b/core/java/com/android/internal/widget/EditableInputConnection.java
@@ -83,13 +83,9 @@
return false;
}
- /**
- * @hide
- */
@Override
- public void reportFinish() {
- super.reportFinish();
-
+ public void closeConnection() {
+ super.closeConnection();
synchronized(this) {
while (mBatchEditNesting > 0) {
endBatchEdit();
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index 9d14478..3d892af 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -1099,7 +1099,8 @@
|| mode == DevicePolicyManager.PASSWORD_QUALITY_NUMERIC
|| mode == DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX
|| mode == DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC
- || mode == DevicePolicyManager.PASSWORD_QUALITY_COMPLEX;
+ || mode == DevicePolicyManager.PASSWORD_QUALITY_COMPLEX
+ || mode == DevicePolicyManager.PASSWORD_QUALITY_MANAGED;
return passwordEnabled && savedPasswordExists(userId);
}
diff --git a/services/core/java/com/android/server/SystemConfig.java b/core/java/com/android/server/SystemConfig.java
similarity index 94%
rename from services/core/java/com/android/server/SystemConfig.java
rename to core/java/com/android/server/SystemConfig.java
index 30e0ceb..07912cd 100644
--- a/services/core/java/com/android/server/SystemConfig.java
+++ b/core/java/com/android/server/SystemConfig.java
@@ -19,6 +19,7 @@
import static com.android.internal.util.ArrayUtils.appendInt;
import android.app.ActivityManager;
+import android.content.ComponentName;
import android.content.pm.FeatureInfo;
import android.content.pm.PackageManager;
import android.os.Environment;
@@ -115,6 +116,9 @@
// These are the packages that should not run under system user
final ArraySet<String> mSystemUserBlacklistedApps = new ArraySet<>();
+ // These are the components that are enabled by default as VR mode listener services.
+ final ArraySet<ComponentName> mDefaultVrComponents = new ArraySet<>();
+
public static SystemConfig getInstance() {
synchronized (SystemConfig.class) {
if (sInstance == null) {
@@ -168,6 +172,10 @@
return mSystemUserBlacklistedApps;
}
+ public ArraySet<ComponentName> getDefaultVrComponents() {
+ return mDefaultVrComponents;
+ }
+
SystemConfig() {
// Read configuration from system
readPermissions(Environment.buildPath(
@@ -431,6 +439,19 @@
mSystemUserBlacklistedApps.add(pkgname);
}
XmlUtils.skipCurrentTag(parser);
+ } else if ("default-enabled-vr-app".equals(name) && allowAppConfigs) {
+ String pkgname = parser.getAttributeValue(null, "package");
+ String clsname = parser.getAttributeValue(null, "class");
+ if (pkgname == null) {
+ Slog.w(TAG, "<default-enabled-vr-app without package in " + permFile
+ + " at " + parser.getPositionDescription());
+ } else if (clsname == null) {
+ Slog.w(TAG, "<default-enabled-vr-app without class in " + permFile
+ + " at " + parser.getPositionDescription());
+ } else {
+ mDefaultVrComponents.add(new ComponentName(pkgname, clsname));
+ }
+ XmlUtils.skipCurrentTag(parser);
} else {
XmlUtils.skipCurrentTag(parser);
continue;
diff --git a/core/java/com/android/server/backup/ShortcutBackupHelper.java b/core/java/com/android/server/backup/ShortcutBackupHelper.java
new file mode 100644
index 0000000..0b3f2ae
--- /dev/null
+++ b/core/java/com/android/server/backup/ShortcutBackupHelper.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.server.backup;
+
+import android.app.backup.BlobBackupHelper;
+import android.content.Context;
+import android.content.pm.IShortcutService;
+import android.os.ServiceManager;
+import android.os.UserHandle;
+import android.util.Slog;
+
+public class ShortcutBackupHelper extends BlobBackupHelper {
+ private static final String TAG = "ShortcutBackupAgent";
+ private static final int BLOB_VERSION = 1;
+
+ private static final String KEY_USER_FILE = "shortcutuser.xml";
+
+ public ShortcutBackupHelper() {
+ super(BLOB_VERSION, KEY_USER_FILE);
+ }
+
+ private IShortcutService getShortcutService() {
+ return IShortcutService.Stub.asInterface(
+ ServiceManager.getService(Context.SHORTCUT_SERVICE));
+ }
+
+ @Override
+ protected byte[] getBackupPayload(String key) {
+ switch (key) {
+ case KEY_USER_FILE:
+ try {
+ return getShortcutService().getBackupPayload(UserHandle.USER_SYSTEM);
+ } catch (Exception e) {
+ Slog.wtf(TAG, "Backup failed", e);
+ }
+ break;
+ default:
+ Slog.w(TAG, "Unknown key: " + key);
+ }
+ return null;
+ }
+
+ @Override
+ protected void applyRestoredPayload(String key, byte[] payload) {
+ switch (key) {
+ case KEY_USER_FILE:
+ try {
+ getShortcutService().applyRestore(payload, UserHandle.USER_SYSTEM);
+ } catch (Exception e) {
+ Slog.wtf(TAG, "Restore failed", e);
+ }
+ break;
+ default:
+ Slog.w(TAG, "Unknown key: " + key);
+ }
+ }
+}
diff --git a/core/java/com/android/server/backup/SystemBackupAgent.java b/core/java/com/android/server/backup/SystemBackupAgent.java
index 181ed51..2d12fcd 100644
--- a/core/java/com/android/server/backup/SystemBackupAgent.java
+++ b/core/java/com/android/server/backup/SystemBackupAgent.java
@@ -17,9 +17,9 @@
package com.android.server.backup;
import android.app.IWallpaperManager;
+import android.app.backup.BackupAgentHelper;
import android.app.backup.BackupDataInput;
import android.app.backup.BackupDataOutput;
-import android.app.backup.BackupAgentHelper;
import android.app.backup.FullBackup;
import android.app.backup.FullBackupDataOutput;
import android.app.backup.WallpaperBackupHelper;
@@ -48,6 +48,7 @@
private static final String NOTIFICATION_HELPER = "notifications";
private static final String PERMISSION_HELPER = "permissions";
private static final String USAGE_STATS_HELPER = "usage_stats";
+ private static final String SHORTCUT_MANAGER_HELPER = "shortcut_manager";
// These paths must match what the WallpaperManagerService uses. The leaf *_FILENAME
// are also used in the full-backup file format, so must not change unless steps are
@@ -100,6 +101,7 @@
addHelper(NOTIFICATION_HELPER, new NotificationBackupHelper(this));
addHelper(PERMISSION_HELPER, new PermissionBackupHelper());
addHelper(USAGE_STATS_HELPER, new UsageStatsBackupHelper(this));
+ addHelper(SHORTCUT_MANAGER_HELPER, new ShortcutBackupHelper());
super.onBackup(oldState, data, newState);
}
@@ -138,6 +140,7 @@
addHelper(NOTIFICATION_HELPER, new NotificationBackupHelper(this));
addHelper(PERMISSION_HELPER, new PermissionBackupHelper());
addHelper(USAGE_STATS_HELPER, new UsageStatsBackupHelper(this));
+ addHelper(SHORTCUT_MANAGER_HELPER, new ShortcutBackupHelper());
try {
super.onRestore(data, appVersionCode, newState);
diff --git a/core/java/com/android/server/net/NetlinkTracker.java b/core/java/com/android/server/net/NetlinkTracker.java
index d45982e..5b421d9 100644
--- a/core/java/com/android/server/net/NetlinkTracker.java
+++ b/core/java/com/android/server/net/NetlinkTracker.java
@@ -102,6 +102,19 @@
}
@Override
+ public void interfaceRemoved(String iface) {
+ maybeLog("interfaceRemoved", iface);
+ if (mInterfaceName.equals(iface)) {
+ // Our interface was removed. Clear our LinkProperties and tell our owner that they are
+ // now empty. Note that from the moment that the interface is removed, any further
+ // interface-specific messages (e.g., RTM_DELADDR) will not reach us, because the netd
+ // code that parses them will not be able to resolve the ifindex to an interface name.
+ clearLinkProperties();
+ mCallback.update();
+ }
+ }
+
+ @Override
public void addressUpdated(String iface, LinkAddress address) {
if (mInterfaceName.equals(iface)) {
maybeLog("addressUpdated", iface, address);
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index c6112d9..8a512a6 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -103,7 +103,6 @@
android_util_jar_StrictJarFile.cpp \
android_graphics_Canvas.cpp \
android_graphics_Picture.cpp \
- android/graphics/AvoidXfermode.cpp \
android/graphics/Bitmap.cpp \
android/graphics/BitmapFactory.cpp \
android/graphics/Camera.cpp \
diff --git a/core/jni/android/graphics/AvoidXfermode.cpp b/core/jni/android/graphics/AvoidXfermode.cpp
deleted file mode 100644
index 9ca1f26..0000000
--- a/core/jni/android/graphics/AvoidXfermode.cpp
+++ /dev/null
@@ -1,177 +0,0 @@
-/*
- * Copyright 2006 The Android Open Source Project
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#include "AvoidXfermode.h"
-#include "SkColorPriv.h"
-#include "SkReadBuffer.h"
-#include "SkWriteBuffer.h"
-#include "SkString.h"
-
-AvoidXfermode::AvoidXfermode(SkColor opColor, U8CPU tolerance, Mode mode) {
- if (tolerance > 255) {
- tolerance = 255;
- }
- fTolerance = SkToU8(tolerance);
- fOpColor = opColor;
- fDistMul = (256 << 14) / (tolerance + 1);
- fMode = mode;
-}
-
-SkFlattenable* AvoidXfermode::CreateProc(SkReadBuffer& buffer) {
- const SkColor color = buffer.readColor();
- const unsigned tolerance = buffer.readUInt();
- const unsigned mode = buffer.readUInt();
- return Create(color, tolerance, (Mode)mode);
-}
-
-void AvoidXfermode::flatten(SkWriteBuffer& buffer) const {
- buffer.writeColor(fOpColor);
- buffer.writeUInt(fTolerance);
- buffer.writeUInt(fMode);
-}
-
-// returns 0..31
-static unsigned color_dist16(uint16_t c, unsigned r, unsigned g, unsigned b) {
- SkASSERT(r <= SK_R16_MASK);
- SkASSERT(g <= SK_G16_MASK);
- SkASSERT(b <= SK_B16_MASK);
-
- unsigned dr = SkAbs32(SkGetPackedR16(c) - r);
- unsigned dg = SkAbs32(SkGetPackedG16(c) - g) >> (SK_G16_BITS - SK_R16_BITS);
- unsigned db = SkAbs32(SkGetPackedB16(c) - b);
-
- return SkMax32(dr, SkMax32(dg, db));
-}
-
-// returns 0..255
-static unsigned color_dist32(SkPMColor c, U8CPU r, U8CPU g, U8CPU b) {
- SkASSERT(r <= 0xFF);
- SkASSERT(g <= 0xFF);
- SkASSERT(b <= 0xFF);
-
- unsigned dr = SkAbs32(SkGetPackedR32(c) - r);
- unsigned dg = SkAbs32(SkGetPackedG32(c) - g);
- unsigned db = SkAbs32(SkGetPackedB32(c) - b);
-
- return SkMax32(dr, SkMax32(dg, db));
-}
-
-static int scale_dist_14(int dist, uint32_t mul, uint32_t sub) {
- int tmp = dist * mul - sub;
- int result = (tmp + (1 << 13)) >> 14;
-
- return result;
-}
-
-static inline unsigned Accurate255To256(unsigned x) {
- return x + (x >> 7);
-}
-
-void AvoidXfermode::xfer32(SkPMColor dst[], const SkPMColor src[], int count,
- const SkAlpha aa[]) const {
- unsigned opR = SkColorGetR(fOpColor);
- unsigned opG = SkColorGetG(fOpColor);
- unsigned opB = SkColorGetB(fOpColor);
- uint32_t mul = fDistMul;
- uint32_t sub = (fDistMul - (1 << 14)) << 8;
-
- int MAX, mask;
-
- if (kTargetColor_Mode == fMode) {
- mask = -1;
- MAX = 255;
- } else {
- mask = 0;
- MAX = 0;
- }
-
- for (int i = 0; i < count; i++) {
- int d = color_dist32(dst[i], opR, opG, opB);
- // now reverse d if we need to
- d = MAX + (d ^ mask) - mask;
- SkASSERT((unsigned)d <= 255);
- d = Accurate255To256(d);
-
- d = scale_dist_14(d, mul, sub);
- SkASSERT(d <= 256);
-
- if (d > 0) {
- if (aa) {
- d = SkAlphaMul(d, Accurate255To256(*aa++));
- if (0 == d) {
- continue;
- }
- }
- dst[i] = SkFourByteInterp256(src[i], dst[i], d);
- }
- }
-}
-
-static inline U16CPU SkBlend3216(SkPMColor src, U16CPU dst, unsigned scale) {
- SkASSERT(scale <= 32);
- scale <<= 3;
-
- return SkPackRGB16( SkAlphaBlend(SkPacked32ToR16(src), SkGetPackedR16(dst), scale),
- SkAlphaBlend(SkPacked32ToG16(src), SkGetPackedG16(dst), scale),
- SkAlphaBlend(SkPacked32ToB16(src), SkGetPackedB16(dst), scale));
-}
-
-void AvoidXfermode::xfer16(uint16_t dst[], const SkPMColor src[], int count,
- const SkAlpha aa[]) const {
- unsigned opR = SkColorGetR(fOpColor) >> (8 - SK_R16_BITS);
- unsigned opG = SkColorGetG(fOpColor) >> (8 - SK_G16_BITS);
- unsigned opB = SkColorGetB(fOpColor) >> (8 - SK_R16_BITS);
- uint32_t mul = fDistMul;
- uint32_t sub = (fDistMul - (1 << 14)) << SK_R16_BITS;
-
- int MAX, mask;
-
- if (kTargetColor_Mode == fMode) {
- mask = -1;
- MAX = 31;
- } else {
- mask = 0;
- MAX = 0;
- }
-
- for (int i = 0; i < count; i++) {
- int d = color_dist16(dst[i], opR, opG, opB);
- // now reverse d if we need to
- d = MAX + (d ^ mask) - mask;
- SkASSERT((unsigned)d <= 31);
- // convert from 0..31 to 0..32
- d += d >> 4;
- d = scale_dist_14(d, mul, sub);
- SkASSERT(d <= 32);
-
- if (d > 0) {
- if (aa) {
- d = SkAlphaMul(d, Accurate255To256(*aa++));
- if (0 == d) {
- continue;
- }
- }
- dst[i] = SkBlend3216(src[i], dst[i], d);
- }
- }
-}
-
-void AvoidXfermode::xferA8(SkAlpha dst[], const SkPMColor src[], int count,
- const SkAlpha aa[]) const {
-}
-
-#ifndef SK_IGNORE_TO_STRING
-void AvoidXfermode::toString(SkString* str) const {
- str->append("AvoidXfermode: opColor: ");
- str->appendHex(fOpColor);
- str->appendf("distMul: %d ", fDistMul);
-
- static const char* gModeStrings[] = { "Avoid", "Target" };
-
- str->appendf("mode: %s", gModeStrings[fMode]);
-}
-#endif
diff --git a/core/jni/android/graphics/AvoidXfermode.h b/core/jni/android/graphics/AvoidXfermode.h
deleted file mode 100644
index 8b7fb71..0000000
--- a/core/jni/android/graphics/AvoidXfermode.h
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Copyright 2006 The Android Open Source Project
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#ifndef AvoidXfermode_DEFINED
-#define AvoidXfermode_DEFINED
-
-#include "SkColor.h"
-#include "SkTypes.h"
-#include "SkXfermode.h"
-
-/** \class AvoidXfermode
-
- This xfermode will draw the src everywhere except on top of the specified
- color.
-*/
-class AvoidXfermode : public SkXfermode {
-public:
- enum Mode {
- kAvoidColor_Mode, //!< draw everywhere except on the opColor
- kTargetColor_Mode //!< draw only on top of the opColor
- };
-
- /** This xfermode draws, or doesn't draw, based on the destination's
- distance from an op-color.
-
- There are two modes, and each mode interprets a tolerance value.
-
- Avoid: In this mode, drawing is allowed only on destination pixels that
- are different from the op-color.
- Tolerance near 0: avoid any colors even remotely similar to the op-color
- Tolerance near 255: avoid only colors nearly identical to the op-color
-
- Target: In this mode, drawing only occurs on destination pixels that
- are similar to the op-color
- Tolerance near 0: draw only on colors that are nearly identical to the op-color
- Tolerance near 255: draw on any colors even remotely similar to the op-color
- */
- static AvoidXfermode* Create(SkColor opColor, U8CPU tolerance, Mode mode) {
- return new AvoidXfermode(opColor, tolerance, mode);
- }
-
- // overrides from SkXfermode
- void xfer32(SkPMColor dst[], const SkPMColor src[], int count,
- const SkAlpha aa[]) const override;
- void xfer16(uint16_t dst[], const SkPMColor src[], int count,
- const SkAlpha aa[]) const override;
- void xferA8(SkAlpha dst[], const SkPMColor src[], int count,
- const SkAlpha aa[]) const override;
-
- SK_TO_STRING_OVERRIDE()
- SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(AvoidXfermode)
-
-protected:
- AvoidXfermode(SkColor opColor, U8CPU tolerance, Mode mode);
- void flatten(SkWriteBuffer&) const override;
-
-private:
- SkColor fOpColor;
- uint32_t fDistMul; // x.14 cached from fTolerance
- uint8_t fTolerance;
- Mode fMode;
-
- typedef SkXfermode INHERITED;
-};
-
-#endif
diff --git a/core/jni/android/graphics/Bitmap.cpp b/core/jni/android/graphics/Bitmap.cpp
index 27b9830..22a81d4 100755
--- a/core/jni/android/graphics/Bitmap.cpp
+++ b/core/jni/android/graphics/Bitmap.cpp
@@ -251,13 +251,6 @@
void Bitmap::reconfigure(const SkImageInfo& info, size_t rowBytes,
SkColorTable* ctable) {
- {
- android::AutoMutex _lock(mLock);
- if (mPinnedRefCount) {
- ALOGW("Called reconfigure on a bitmap that is in use! This may"
- " cause graphical corruption!");
- }
- }
mPixelRef->reconfigure(info, rowBytes, ctable);
}
diff --git a/core/jni/android/graphics/Paint.cpp b/core/jni/android/graphics/Paint.cpp
index 27d8fed..1844a98 100644
--- a/core/jni/android/graphics/Paint.cpp
+++ b/core/jni/android/graphics/Paint.cpp
@@ -823,7 +823,7 @@
static jfloat doRunAdvance(const Paint* paint, Typeface* typeface, const jchar buf[],
jint start, jint count, jint bufSize, jboolean isRtl, jint offset) {
int bidiFlags = isRtl ? kBidi_Force_RTL : kBidi_Force_LTR;
- if (offset == count) {
+ if (offset == start + count) {
return MinikinUtils::measureText(paint, bidiFlags, typeface, buf, start, count,
bufSize, nullptr);
}
diff --git a/core/jni/android_graphics_drawable_VectorDrawable.cpp b/core/jni/android_graphics_drawable_VectorDrawable.cpp
index a2662f9..b04293e 100644
--- a/core/jni/android_graphics_drawable_VectorDrawable.cpp
+++ b/core/jni/android_graphics_drawable_VectorDrawable.cpp
@@ -14,11 +14,11 @@
* limitations under the License.
*/
-#include "jni.h"
#include "GraphicsJNI.h"
+#include "jni.h"
#include "core_jni_helpers.h"
-#include "log/log.h"
+#include "PathParser.h"
#include "VectorDrawable.h"
#include <hwui/Paint.h>
@@ -27,43 +27,15 @@
using namespace uirenderer;
using namespace uirenderer::VectorDrawable;
+/**
+ * VectorDrawable's pre-draw construction.
+ */
static jlong createTree(JNIEnv*, jobject, jlong groupPtr) {
VectorDrawable::Group* rootGroup = reinterpret_cast<VectorDrawable::Group*>(groupPtr);
VectorDrawable::Tree* tree = new VectorDrawable::Tree(rootGroup);
return reinterpret_cast<jlong>(tree);
}
-static void setTreeViewportSize(JNIEnv*, jobject, jlong treePtr,
- jfloat viewportWidth, jfloat viewportHeight) {
- VectorDrawable::Tree* tree = reinterpret_cast<VectorDrawable::Tree*>(treePtr);
- tree->setViewportSize(viewportWidth, viewportHeight);
-}
-
-static jboolean setRootAlpha(JNIEnv*, jobject, jlong treePtr, jfloat alpha) {
- VectorDrawable::Tree* tree = reinterpret_cast<VectorDrawable::Tree*>(treePtr);
- return tree->setRootAlpha(alpha);
-}
-
-static jfloat getRootAlpha(JNIEnv*, jobject, jlong treePtr) {
- VectorDrawable::Tree* tree = reinterpret_cast<VectorDrawable::Tree*>(treePtr);
- return tree->getRootAlpha();
-}
-
-static void setAllowCaching(JNIEnv*, jobject, jlong treePtr, jboolean allowCaching) {
- VectorDrawable::Tree* tree = reinterpret_cast<VectorDrawable::Tree*>(treePtr);
- tree->setAllowCaching(allowCaching);
-}
-
-static void draw(JNIEnv* env, jobject, jlong treePtr, jlong canvasPtr,
- jlong colorFilterPtr, jobject jrect, jboolean needsMirroring, jboolean canReuseCache) {
- VectorDrawable::Tree* tree = reinterpret_cast<VectorDrawable::Tree*>(treePtr);
- Canvas* canvas = reinterpret_cast<Canvas*>(canvasPtr);
- SkRect rect;
- GraphicsJNI::jrect_to_rect(env, jrect, &rect);
- SkColorFilter* colorFilter = reinterpret_cast<SkColorFilter*>(colorFilterPtr);
- tree->draw(canvas, colorFilter, rect, needsMirroring, canReuseCache);
-}
-
static jlong createEmptyFullPath(JNIEnv*, jobject) {
VectorDrawable::FullPath* newPath = new VectorDrawable::FullPath();
return reinterpret_cast<jlong>(newPath);
@@ -76,46 +48,6 @@
return reinterpret_cast<jlong>(newPath);
}
-static void updateFullPathPropertiesAndStrokeStyles(JNIEnv*, jobject, jlong fullPathPtr,
- jfloat strokeWidth, jint strokeColor, jfloat strokeAlpha, jint fillColor, jfloat fillAlpha,
- jfloat trimPathStart, jfloat trimPathEnd, jfloat trimPathOffset, jfloat strokeMiterLimit,
- jint strokeLineCap, jint strokeLineJoin, jint fillType) {
- VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
- fullPath->updateProperties(strokeWidth, strokeColor, strokeAlpha, fillColor, fillAlpha,
- trimPathStart, trimPathEnd, trimPathOffset, strokeMiterLimit, strokeLineCap,
- strokeLineJoin, fillType);
-}
-
-static void updateFullPathFillGradient(JNIEnv*, jobject, jlong pathPtr, jlong fillGradientPtr) {
- VectorDrawable::FullPath* path = reinterpret_cast<VectorDrawable::FullPath*>(pathPtr);
- SkShader* fillShader = reinterpret_cast<SkShader*>(fillGradientPtr);
- path->setFillGradient(fillShader);
-}
-
-static void updateFullPathStrokeGradient(JNIEnv*, jobject, jlong pathPtr, jlong strokeGradientPtr) {
- VectorDrawable::FullPath* path = reinterpret_cast<VectorDrawable::FullPath*>(pathPtr);
- SkShader* strokeShader = reinterpret_cast<SkShader*>(strokeGradientPtr);
- path->setStrokeGradient(strokeShader);
-}
-
-static jboolean getFullPathProperties(JNIEnv* env, jobject, jlong fullPathPtr,
- jbyteArray outProperties, jint length) {
- VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
- int8_t pathProperties[length];
- bool success = fullPath->getProperties(pathProperties, length);
- env->SetByteArrayRegion(outProperties, 0, length, reinterpret_cast<int8_t*>(&pathProperties));
- return success;
-}
-
-static jboolean getGroupProperties(JNIEnv* env, jobject, jlong groupPtr,
- jfloatArray outProperties, jint length) {
- VectorDrawable::Group* group = reinterpret_cast<VectorDrawable::Group*>(groupPtr);
- float groupProperties[length];
- bool success = group->getProperties(groupProperties, length);
- env->SetFloatArrayRegion(outProperties, 0, length, reinterpret_cast<float*>(&groupProperties));
- return success;
-}
-
static jlong createEmptyClipPath(JNIEnv*, jobject) {
VectorDrawable::ClipPath* newPath = new VectorDrawable::ClipPath();
return reinterpret_cast<jlong>(newPath);
@@ -146,180 +78,265 @@
env->ReleaseStringUTFChars(nameStr, nodeName);
}
-static void updateGroupProperties(JNIEnv*, jobject, jlong groupPtr, jfloat rotate, jfloat pivotX,
- jfloat pivotY, jfloat scaleX, jfloat scaleY, jfloat translateX, jfloat translateY) {
- VectorDrawable::Group* group = reinterpret_cast<VectorDrawable::Group*>(groupPtr);
- group->updateLocalMatrix(rotate, pivotX, pivotY, scaleX, scaleY, translateX, translateY);
-}
-
static void addChild(JNIEnv*, jobject, jlong groupPtr, jlong childPtr) {
VectorDrawable::Group* group = reinterpret_cast<VectorDrawable::Group*>(groupPtr);
VectorDrawable::Node* child = reinterpret_cast<VectorDrawable::Node*>(childPtr);
group->addChild(child);
}
+static void setAllowCaching(JNIEnv*, jobject, jlong treePtr, jboolean allowCaching) {
+ VectorDrawable::Tree* tree = reinterpret_cast<VectorDrawable::Tree*>(treePtr);
+ tree->setAllowCaching(allowCaching);
+}
+
+/**
+ * Draw
+ */
+static void draw(JNIEnv* env, jobject, jlong treePtr, jlong canvasPtr,
+ jlong colorFilterPtr, jobject jrect, jboolean needsMirroring, jboolean canReuseCache) {
+ VectorDrawable::Tree* tree = reinterpret_cast<VectorDrawable::Tree*>(treePtr);
+ Canvas* canvas = reinterpret_cast<Canvas*>(canvasPtr);
+ SkRect rect;
+ GraphicsJNI::jrect_to_rect(env, jrect, &rect);
+ SkColorFilter* colorFilter = reinterpret_cast<SkColorFilter*>(colorFilterPtr);
+ tree->draw(canvas, colorFilter, rect, needsMirroring, canReuseCache);
+}
+
+/**
+ * Setters and getters for updating staging properties that can happen both pre-draw and post draw.
+ */
+static void setTreeViewportSize(JNIEnv*, jobject, jlong treePtr,
+ jfloat viewportWidth, jfloat viewportHeight) {
+ VectorDrawable::Tree* tree = reinterpret_cast<VectorDrawable::Tree*>(treePtr);
+ tree->mutateStagingProperties()->setViewportSize(viewportWidth, viewportHeight);
+}
+
+static jboolean setRootAlpha(JNIEnv*, jobject, jlong treePtr, jfloat alpha) {
+ VectorDrawable::Tree* tree = reinterpret_cast<VectorDrawable::Tree*>(treePtr);
+ return tree->mutateStagingProperties()->setRootAlpha(alpha);
+}
+
+static jfloat getRootAlpha(JNIEnv*, jobject, jlong treePtr) {
+ VectorDrawable::Tree* tree = reinterpret_cast<VectorDrawable::Tree*>(treePtr);
+ return tree->stagingProperties()->getRootAlpha();
+}
+
+static void updateFullPathPropertiesAndStrokeStyles(JNIEnv*, jobject, jlong fullPathPtr,
+ jfloat strokeWidth, jint strokeColor, jfloat strokeAlpha, jint fillColor, jfloat fillAlpha,
+ jfloat trimPathStart, jfloat trimPathEnd, jfloat trimPathOffset, jfloat strokeMiterLimit,
+ jint strokeLineCap, jint strokeLineJoin, jint fillType) {
+ VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
+ fullPath->mutateStagingProperties()->updateProperties(strokeWidth, strokeColor, strokeAlpha,
+ fillColor, fillAlpha, trimPathStart, trimPathEnd, trimPathOffset, strokeMiterLimit,
+ strokeLineCap, strokeLineJoin, fillType);
+}
+
+static void updateFullPathFillGradient(JNIEnv*, jobject, jlong pathPtr, jlong fillGradientPtr) {
+ VectorDrawable::FullPath* path = reinterpret_cast<VectorDrawable::FullPath*>(pathPtr);
+ SkShader* fillShader = reinterpret_cast<SkShader*>(fillGradientPtr);
+ path->mutateStagingProperties()->setFillGradient(fillShader);
+}
+
+static void updateFullPathStrokeGradient(JNIEnv*, jobject, jlong pathPtr, jlong strokeGradientPtr) {
+ VectorDrawable::FullPath* path = reinterpret_cast<VectorDrawable::FullPath*>(pathPtr);
+ SkShader* strokeShader = reinterpret_cast<SkShader*>(strokeGradientPtr);
+ path->mutateStagingProperties()->setStrokeGradient(strokeShader);
+}
+
+static jboolean getFullPathProperties(JNIEnv* env, jobject, jlong fullPathPtr,
+ jbyteArray outProperties, jint length) {
+ VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
+ int8_t pathProperties[length];
+ bool success = fullPath->stagingProperties()->copyProperties(pathProperties, length);
+ env->SetByteArrayRegion(outProperties, 0, length, reinterpret_cast<int8_t*>(&pathProperties));
+ return success;
+}
+
+static jboolean getGroupProperties(JNIEnv* env, jobject, jlong groupPtr,
+ jfloatArray outProperties, jint length) {
+ VectorDrawable::Group* group = reinterpret_cast<VectorDrawable::Group*>(groupPtr);
+ float groupProperties[length];
+ bool success = group->stagingProperties()->copyProperties(groupProperties, length);
+ env->SetFloatArrayRegion(outProperties, 0, length, reinterpret_cast<float*>(&groupProperties));
+ return success;
+}
+
+static void updateGroupProperties(JNIEnv*, jobject, jlong groupPtr, jfloat rotate, jfloat pivotX,
+ jfloat pivotY, jfloat scaleX, jfloat scaleY, jfloat translateX, jfloat translateY) {
+ VectorDrawable::Group* group = reinterpret_cast<VectorDrawable::Group*>(groupPtr);
+ group->mutateStagingProperties()->updateProperties(rotate, pivotX, pivotY, scaleX, scaleY,
+ translateX, translateY);
+}
+
static void setPathString(JNIEnv* env, jobject, jlong pathPtr, jstring inputStr,
jint stringLength) {
VectorDrawable::Path* path = reinterpret_cast<VectorDrawable::Path*>(pathPtr);
const char* pathString = env->GetStringUTFChars(inputStr, NULL);
- path->setPath(pathString, stringLength);
+
+ PathParser::ParseResult result;
+ PathData data;
+ PathParser::getPathDataFromString(&data, &result, pathString, stringLength);
+ path->mutateStagingProperties()->setData(data);
env->ReleaseStringUTFChars(inputStr, pathString);
}
+/**
+ * Setters and getters that should only be called from animation thread for animation purpose.
+ */
static jfloat getRotation(JNIEnv*, jobject, jlong groupPtr) {
VectorDrawable::Group* group = reinterpret_cast<VectorDrawable::Group*>(groupPtr);
- return group->getRotation();
+ return group->stagingProperties()->getRotation();
}
static void setRotation(JNIEnv*, jobject, jlong groupPtr, jfloat rotation) {
VectorDrawable::Group* group = reinterpret_cast<VectorDrawable::Group*>(groupPtr);
- group->setRotation(rotation);
+ group->mutateStagingProperties()->setRotation(rotation);
}
static jfloat getPivotX(JNIEnv*, jobject, jlong groupPtr) {
VectorDrawable::Group* group = reinterpret_cast<VectorDrawable::Group*>(groupPtr);
- return group->getPivotX();
+ return group->stagingProperties()->getPivotX();
}
static void setPivotX(JNIEnv*, jobject, jlong groupPtr, jfloat pivotX) {
VectorDrawable::Group* group = reinterpret_cast<VectorDrawable::Group*>(groupPtr);
- group->setPivotX(pivotX);
+ group->mutateStagingProperties()->setPivotX(pivotX);
}
static jfloat getPivotY(JNIEnv*, jobject, jlong groupPtr) {
VectorDrawable::Group* group = reinterpret_cast<VectorDrawable::Group*>(groupPtr);
- return group->getPivotY();
+ return group->stagingProperties()->getPivotY();
}
static void setPivotY(JNIEnv*, jobject, jlong groupPtr, jfloat pivotY) {
VectorDrawable::Group* group = reinterpret_cast<VectorDrawable::Group*>(groupPtr);
- group->setPivotY(pivotY);
+ group->mutateStagingProperties()->setPivotY(pivotY);
}
static jfloat getScaleX(JNIEnv*, jobject, jlong groupPtr) {
VectorDrawable::Group* group = reinterpret_cast<VectorDrawable::Group*>(groupPtr);
- return group->getScaleX();
+ return group->stagingProperties()->getScaleX();
}
static void setScaleX(JNIEnv*, jobject, jlong groupPtr, jfloat scaleX) {
VectorDrawable::Group* group = reinterpret_cast<VectorDrawable::Group*>(groupPtr);
- group->setScaleX(scaleX);
+ group->mutateStagingProperties()->setScaleX(scaleX);
}
static jfloat getScaleY(JNIEnv*, jobject, jlong groupPtr) {
VectorDrawable::Group* group = reinterpret_cast<VectorDrawable::Group*>(groupPtr);
- return group->getScaleY();
+ return group->stagingProperties()->getScaleY();
}
static void setScaleY(JNIEnv*, jobject, jlong groupPtr, jfloat scaleY) {
VectorDrawable::Group* group = reinterpret_cast<VectorDrawable::Group*>(groupPtr);
- group->setScaleY(scaleY);
+ group->mutateStagingProperties()->setScaleY(scaleY);
}
static jfloat getTranslateX(JNIEnv*, jobject, jlong groupPtr) {
VectorDrawable::Group* group = reinterpret_cast<VectorDrawable::Group*>(groupPtr);
- return group->getTranslateX();
+ return group->stagingProperties()->getTranslateX();
}
static void setTranslateX(JNIEnv*, jobject, jlong groupPtr, jfloat translateX) {
VectorDrawable::Group* group = reinterpret_cast<VectorDrawable::Group*>(groupPtr);
- group->setTranslateX(translateX);
+ group->mutateStagingProperties()->setTranslateX(translateX);
}
static jfloat getTranslateY(JNIEnv*, jobject, jlong groupPtr) {
VectorDrawable::Group* group = reinterpret_cast<VectorDrawable::Group*>(groupPtr);
- return group->getTranslateY();
+ return group->stagingProperties()->getTranslateY();
}
static void setTranslateY(JNIEnv*, jobject, jlong groupPtr, jfloat translateY) {
VectorDrawable::Group* group = reinterpret_cast<VectorDrawable::Group*>(groupPtr);
- group->setTranslateY(translateY);
+ group->mutateStagingProperties()->setTranslateY(translateY);
}
static void setPathData(JNIEnv*, jobject, jlong pathPtr, jlong pathDataPtr) {
VectorDrawable::Path* path = reinterpret_cast<VectorDrawable::Path*>(pathPtr);
PathData* pathData = reinterpret_cast<PathData*>(pathDataPtr);
- path->setPathData(*pathData);
+ path->mutateStagingProperties()->setData(*pathData);
}
static jfloat getStrokeWidth(JNIEnv*, jobject, jlong fullPathPtr) {
VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
- return fullPath->getStrokeWidth();
+ return fullPath->stagingProperties()->getStrokeWidth();
}
static void setStrokeWidth(JNIEnv*, jobject, jlong fullPathPtr, jfloat strokeWidth) {
VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
- fullPath->setStrokeWidth(strokeWidth);
+ fullPath->mutateStagingProperties()->setStrokeWidth(strokeWidth);
}
static jint getStrokeColor(JNIEnv*, jobject, jlong fullPathPtr) {
VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
- return fullPath->getStrokeColor();
+ return fullPath->stagingProperties()->getStrokeColor();
}
static void setStrokeColor(JNIEnv*, jobject, jlong fullPathPtr, jint strokeColor) {
VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
- fullPath->setStrokeColor(strokeColor);
+ fullPath->mutateStagingProperties()->setStrokeColor(strokeColor);
}
static jfloat getStrokeAlpha(JNIEnv*, jobject, jlong fullPathPtr) {
VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
- return fullPath->getStrokeAlpha();
+ return fullPath->stagingProperties()->getStrokeAlpha();
}
static void setStrokeAlpha(JNIEnv*, jobject, jlong fullPathPtr, jfloat strokeAlpha) {
VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
- fullPath->setStrokeAlpha(strokeAlpha);
+ fullPath->mutateStagingProperties()->setStrokeAlpha(strokeAlpha);
}
static jint getFillColor(JNIEnv*, jobject, jlong fullPathPtr) {
VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
- return fullPath->getFillColor();
+ return fullPath->stagingProperties()->getFillColor();
}
static void setFillColor(JNIEnv*, jobject, jlong fullPathPtr, jint fillColor) {
VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
- fullPath->setFillColor(fillColor);
+ fullPath->mutateStagingProperties()->setFillColor(fillColor);
}
static jfloat getFillAlpha(JNIEnv*, jobject, jlong fullPathPtr) {
VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
- return fullPath->getFillAlpha();
+ return fullPath->stagingProperties()->getFillAlpha();
}
static void setFillAlpha(JNIEnv*, jobject, jlong fullPathPtr, jfloat fillAlpha) {
VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
- fullPath->setFillAlpha(fillAlpha);
+ fullPath->mutateStagingProperties()->setFillAlpha(fillAlpha);
}
static jfloat getTrimPathStart(JNIEnv*, jobject, jlong fullPathPtr) {
VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
- return fullPath->getTrimPathStart();
+ return fullPath->stagingProperties()->getTrimPathStart();
}
static void setTrimPathStart(JNIEnv*, jobject, jlong fullPathPtr, jfloat trimPathStart) {
VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
- fullPath->setTrimPathStart(trimPathStart);
+ fullPath->mutateStagingProperties()->setTrimPathStart(trimPathStart);
}
static jfloat getTrimPathEnd(JNIEnv*, jobject, jlong fullPathPtr) {
VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
- return fullPath->getTrimPathEnd();
+ return fullPath->stagingProperties()->getTrimPathEnd();
}
static void setTrimPathEnd(JNIEnv*, jobject, jlong fullPathPtr, jfloat trimPathEnd) {
VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
- fullPath->setTrimPathEnd(trimPathEnd);
+ fullPath->mutateStagingProperties()->setTrimPathEnd(trimPathEnd);
}
static jfloat getTrimPathOffset(JNIEnv*, jobject, jlong fullPathPtr) {
VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
- return fullPath->getTrimPathOffset();
+ return fullPath->stagingProperties()->getTrimPathOffset();
}
static void setTrimPathOffset(JNIEnv*, jobject, jlong fullPathPtr, jfloat trimPathOffset) {
VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
- fullPath->setTrimPathOffset(trimPathOffset);
+ fullPath->mutateStagingProperties()->setTrimPathOffset(trimPathOffset);
}
static const JNINativeMethod gMethods[] = {
diff --git a/core/jni/android_hardware_Camera.cpp b/core/jni/android_hardware_Camera.cpp
index 806fcc3..91f003d 100644
--- a/core/jni/android_hardware_Camera.cpp
+++ b/core/jni/android_hardware_Camera.cpp
@@ -567,6 +567,45 @@
// save context in opaque field
env->SetLongField(thiz, fields.context, (jlong)context.get());
+
+ // Update default display orientation in case the sensor is reverse-landscape
+ CameraInfo cameraInfo;
+ status_t rc = Camera::getCameraInfo(cameraId, &cameraInfo);
+ if (rc != NO_ERROR) {
+ return rc;
+ }
+ int defaultOrientation = 0;
+ switch (cameraInfo.orientation) {
+ case 0:
+ break;
+ case 90:
+ if (cameraInfo.facing == CAMERA_FACING_FRONT) {
+ defaultOrientation = 180;
+ }
+ break;
+ case 180:
+ defaultOrientation = 180;
+ break;
+ case 270:
+ if (cameraInfo.facing != CAMERA_FACING_FRONT) {
+ defaultOrientation = 180;
+ }
+ break;
+ default:
+ ALOGE("Unexpected camera orientation %d!", cameraInfo.orientation);
+ break;
+ }
+ if (defaultOrientation != 0) {
+ ALOGV("Setting default display orientation to %d", defaultOrientation);
+ rc = camera->sendCommand(CAMERA_CMD_SET_DISPLAY_ORIENTATION,
+ defaultOrientation, 0);
+ if (rc != NO_ERROR) {
+ ALOGE("Unable to update default orientation: %s (%d)",
+ strerror(-rc), rc);
+ return rc;
+ }
+ }
+
return NO_ERROR;
}
diff --git a/core/jni/android_hardware_SensorManager.cpp b/core/jni/android_hardware_SensorManager.cpp
index e39bb1c..90f407f 100644
--- a/core/jni/android_hardware_SensorManager.cpp
+++ b/core/jni/android_hardware_SensorManager.cpp
@@ -36,15 +36,17 @@
#include "core_jni_helpers.h"
-static struct {
+namespace {
+
+using namespace android;
+
+struct {
jclass clazz;
jmethodID dispatchSensorEvent;
jmethodID dispatchFlushCompleteEvent;
jmethodID dispatchAdditionalInfoEvent;
} gBaseEventQueueClassInfo;
-namespace android {
-
struct SensorOffsets
{
jclass clazz;
@@ -72,9 +74,9 @@
} gListOffsets;
/*
- * The method below are not thread-safe and not intended to be
+ * nativeClassInit is not inteneded to be thread-safe. It should be called before other native...
+ * functions (except nativeCreate).
*/
-
static void
nativeClassInit (JNIEnv *_env, jclass _this)
{
@@ -494,9 +496,7 @@
(void*)nativeInjectSensorData },
};
-}; // namespace android
-
-using namespace android;
+} //unnamed namespace
int register_android_hardware_SensorManager(JNIEnv *env)
{
diff --git a/core/jni/android_hardware_location_ContextHubService.cpp b/core/jni/android_hardware_location_ContextHubService.cpp
index 8724729..80ae550 100644
--- a/core/jni/android_hardware_location_ContextHubService.cpp
+++ b/core/jni/android_hardware_location_ContextHubService.cpp
@@ -16,23 +16,39 @@
#include "context_hub.h"
+#define LOG_NDEBUG 0
+#define LOG_TAG "ContextHubService"
+
+#include <inttypes.h>
+#include <jni.h>
+#include <map>
+#include <queue>
#include <string.h>
#include <stdint.h>
#include <stdio.h>
+#include <stdlib.h>
-#include <jni.h>
+#include <cutils/log.h>
+
#include "JNIHelp.h"
#include "core_jni_helpers.h"
-#include "stdint.h"
-#include "stdlib.h"
+
+static constexpr int OS_APP_ID=-1;
+
+static constexpr int MIN_APP_ID=1;
+static constexpr int MAX_APP_ID=128;
+
+static constexpr size_t MSG_HEADER_SIZE=4;
+static constexpr int HEADER_FIELD_MSG_TYPE=0;
+//static constexpr int HEADER_FIELD_MSG_VERSION=1;
+static constexpr int HEADER_FIELD_HUB_HANDLE=2;
+static constexpr int HEADER_FIELD_APP_INSTANCE=3;
namespace android {
namespace {
-// TODO: We should share this array_length function widely around Android
-// code.
/*
* Finds the length of a statically-sized array using template trickery that
* also prevents it from being applied to the wrong type.
@@ -64,35 +80,215 @@
jmethodID contextHubInfoSetPeakPowerDrawMw;
jmethodID contextHubInfoSetSupportedSensors;
jmethodID contextHubInfoSetMemoryRegions;
+ jmethodID contextHubInfoSetMaxPacketLenBytes;
jmethodID contextHubServiceMsgReceiptCallback;
+ jmethodID contextHubServiceAddAppInstance;
};
struct context_hub_info_s {
- int cookie;
+ uint32_t *cookies;
int numHubs;
const struct context_hub_t *hubs;
struct context_hub_module_t *contextHubModule;
};
+struct app_instance_info_s {
+ uint32_t hubHandle; // Id of the hub this app is on
+ int instanceId; // systemwide unique instance id - assigned
+ struct hub_app_info appInfo; // returned from the HAL
+ uint64_t truncName; // Possibly truncated name - logging
+};
+
struct contextHubServiceDb_s {
int initialized;
context_hub_info_s hubInfo;
jniInfo_s jniInfo;
+ std::queue<int> freeIds;
+ std::map<int, app_instance_info_s *> appInstances;
};
} // unnamed namespace
static contextHubServiceDb_s db;
-int context_hub_callback(uint32_t hub_id, const struct hub_message_t *msg,
+int context_hub_callback(uint32_t hubId, const struct hub_message_t *msg,
void *cookie);
+const context_hub_t *get_hub_info(int hubHandle) {
+ if (hubHandle >= 0 && hubHandle < db.hubInfo.numHubs) {
+ return &db.hubInfo.hubs[hubHandle];
+ }
+ return nullptr;
+}
+
+static int send_msg_to_hub(const hub_message_t *msg, int hubHandle) {
+ const context_hub_t *info = get_hub_info(hubHandle);
+
+ if (info) {
+ return db.hubInfo.contextHubModule->send_message(info->hub_id, msg);
+ } else {
+ ALOGD("%s: Hub information is null for hubHandle %d", __FUNCTION__, hubHandle);
+ return -1;
+ }
+}
+
+static int set_os_app_as_destination(hub_message_t *msg, int hubHandle) {
+ const context_hub_t *info = get_hub_info(hubHandle);
+
+ if (info) {
+ msg->app = info->os_app_name;
+ return 0;
+ } else {
+ ALOGD("%s: Hub information is null for hubHandle %d", __FUNCTION__, hubHandle);
+ return -1;
+ }
+}
+
+static int get_hub_id_for_hub_handle(int hubHandle) {
+ if (hubHandle < 0 || hubHandle >= db.hubInfo.numHubs) {
+ return -1;
+ } else {
+ return db.hubInfo.hubs[hubHandle].hub_id;
+ }
+}
+
+static int get_hub_id_for_app_instance(int id) {
+ if (db.appInstances.find(id) == db.appInstances.end()) {
+ ALOGD("%s: Cannot find app for app instance %d", __FUNCTION__, id);
+ return -1;
+ }
+
+ int hubHandle = db.appInstances[id]->hubHandle;
+
+ return db.hubInfo.hubs[hubHandle].hub_id;
+}
+
+static int set_dest_app(hub_message_t *msg, int id) {
+ if (db.appInstances.find(id) == db.appInstances.end()) {
+ ALOGD("%s: Cannod find app for app instance %d", __FUNCTION__, id);
+ return -1;
+ }
+
+ msg->app = db.appInstances[id]->appInfo.name;
+ return 0;
+}
+
+static void send_query_for_apps() {
+ hub_message_t msg;
+
+ msg.message_type = CONTEXT_HUB_QUERY_APPS;
+ msg.message_len = 0;
+
+ for (int i = 0; i < db.hubInfo.numHubs; i++ ) {
+ ALOGD("Sending query for apps to hub %d", i);
+ set_os_app_as_destination(&msg, i);
+ if (send_msg_to_hub(&msg, i) != 0) {
+ ALOGW("Could not query hub %i for apps", i);
+ }
+ }
+}
+
+static int return_id(int id) {
+ // Note : This method is not thread safe.
+ // id returned is guarenteed to be in use
+ db.freeIds.push(id);
+ return 0;
+}
+
+static int generate_id(void) {
+ // Note : This method is not thread safe.
+ int retVal = -1;
+
+ if (!db.freeIds.empty()) {
+ retVal = db.freeIds.front();
+ db.freeIds.pop();
+ }
+
+ return retVal;
+}
+
+int add_app_instance(const hub_app_info *appInfo, uint32_t hubHandle, JNIEnv *env) {
+ // Not checking if the apps are indeed distinct
+
+ app_instance_info_s *entry;
+ void *appName;
+ hub_app_name_t *name;
+
+ assert(appInfo && appInfo->name && appInfo->name->app_name);
+
+ entry = (app_instance_info_s *) malloc(sizeof(app_instance_info_s));
+ appName = malloc(appInfo->name->app_name_len);
+ name = (hub_app_name_t *) malloc(sizeof(hub_app_name_t));
+
+ int appInstanceHandle = generate_id();
+
+ if (appInstanceHandle < 0 || !appName || !entry || !name) {
+ ALOGE("Cannot find resources to add app instance %d, %p, %p",
+ appInstanceHandle, appName, entry);
+
+ free(appName);
+ free(entry);
+ free(name);
+
+ if (appInstanceHandle >= 0) {
+ return_id(appInstanceHandle);
+ }
+
+ return -1;
+ }
+
+ memcpy(&(entry->appInfo), appInfo, sizeof(entry->appInfo));
+ memcpy(appName, appInfo->name->app_name, appInfo->name->app_name_len);
+ name->app_name = appName;
+ name->app_name_len = appInfo->name->app_name_len;
+ entry->appInfo.name = name;
+ entry->truncName = 0;
+ memcpy(&(entry->truncName), name->app_name,
+ sizeof(entry->truncName) < name->app_name_len ?
+ sizeof(entry->truncName) : name->app_name_len);
+
+ // Not checking for sanity of hubId
+ entry->hubHandle = hubHandle;
+ entry->instanceId = appInstanceHandle;
+ db.appInstances[appInstanceHandle] = entry;
+
+ // Finally - let the service know of this app instance
+ env->CallIntMethod(db.jniInfo.jContextHubService,
+ db.jniInfo.contextHubServiceAddAppInstance,
+ hubHandle, entry->instanceId, entry->truncName,
+ entry->appInfo.version);
+
+ ALOGW("Added App 0x%" PRIx64 " on hub Handle %" PRId32
+ " as appInstance %d, original name_length %" PRId32, entry->truncName,
+ entry->hubHandle, appInstanceHandle, name->app_name_len);
+
+ return appInstanceHandle;
+}
+
+int delete_app_instance(int id) {
+ if (db.appInstances.find(id) == db.appInstances.end()) {
+ return -1;
+ }
+
+ return_id(id);
+
+ if (db.appInstances[id]) {
+ // Losing the const cast below. This is intentional.
+ free((void *)db.appInstances[id]->appInfo.name->app_name);
+ free((void *)db.appInstances[id]->appInfo.name);
+ free(db.appInstances[id]);
+ db.appInstances.erase(id);
+ }
+
+ return 0;
+}
+
+
static void initContextHubService() {
int err = 0;
- db.hubInfo.hubs = NULL;
+ db.hubInfo.hubs = nullptr;
db.hubInfo.numHubs = 0;
- db.hubInfo.cookie = 0;
int i;
err = hw_get_module(CONTEXT_HUB_MODULE_ID,
@@ -103,26 +299,45 @@
strerror(-err));
}
- if (db.hubInfo.contextHubModule) {
- ALOGD("Fetching hub info");
- db.hubInfo.numHubs = db.hubInfo.contextHubModule->get_hubs(db.hubInfo.contextHubModule,
- &db.hubInfo.hubs);
+ // Prep for storing app info
+ for(i = MIN_APP_ID; i <= MAX_APP_ID; i++) {
+ db.freeIds.push(i);
+ }
- if (db.hubInfo.numHubs > 0) {
- for (i = 0; i < db.hubInfo.numHubs; i++) {
- // TODO : Event though one cookie is OK for now, lets change
- // this to be one per hub
- db.hubInfo.contextHubModule->subscribe_messages(db.hubInfo.hubs[i].hub_id,
- context_hub_callback,
- &db.hubInfo.cookie);
+ if (db.hubInfo.contextHubModule) {
+ int retNumHubs = db.hubInfo.contextHubModule->get_hubs(db.hubInfo.contextHubModule,
+ &db.hubInfo.hubs);
+ ALOGD("ContextHubModule returned %d hubs ", retNumHubs);
+ db.hubInfo.numHubs = retNumHubs;
+
+ if (db.hubInfo.numHubs > 0) {
+ db.hubInfo.numHubs = retNumHubs;
+ db.hubInfo.cookies = (uint32_t *)malloc(sizeof(uint32_t) * db.hubInfo.numHubs);
+
+ if (!db.hubInfo.cookies) {
+ ALOGW("Ran out of memory allocating cookies, bailing");
+ return;
+ }
+
+ for (i = 0; i < db.hubInfo.numHubs; i++) {
+ db.hubInfo.cookies[i] = db.hubInfo.hubs[i].hub_id;
+ if (db.hubInfo.contextHubModule->subscribe_messages(db.hubInfo.hubs[i].hub_id,
+ context_hub_callback,
+ &db.hubInfo.cookies[i]) == 0) {
+ }
+ }
}
- }
+
+ send_query_for_apps();
+ } else {
+ ALOGW("No Context Hub Module present");
}
}
static int onMessageReceipt(int *header, int headerLen, char *msg, int msgLen) {
JNIEnv *env;
- if ((db.jniInfo.vm)->AttachCurrentThread(&env, NULL) != JNI_OK) {
+
+ if ((db.jniInfo.vm)->AttachCurrentThread(&env, nullptr) != JNI_OK) {
return -1;
}
@@ -132,28 +347,131 @@
env->SetByteArrayRegion(jmsg, 0, msgLen, (jbyte *)msg);
env->SetIntArrayRegion(jheader, 0, headerLen, (jint *)header);
-
- return env->CallIntMethod(db.jniInfo.jContextHubService,
+ return (env->CallIntMethod(db.jniInfo.jContextHubService,
db.jniInfo.contextHubServiceMsgReceiptCallback,
- jheader, jmsg);
+ jheader, jmsg) != 0);
}
-int context_hub_callback(uint32_t hub_id, const struct hub_message_t *msg,
+int handle_query_apps_response(char *msg, int msgLen, uint32_t hubHandle) {
+ int i;
+ JNIEnv *env;
+ if ((db.jniInfo.vm)->AttachCurrentThread(&env, nullptr) != JNI_OK) {
+ return -1;
+ }
+
+ int numApps = msgLen/sizeof(hub_app_info);
+ hub_app_info *info = (hub_app_info *)malloc(msgLen); // handle possible alignment
+
+ if (!info) {
+ return -1;
+ }
+
+ memcpy(info, msg, msgLen);
+ for (i = 0; i < numApps; i++) {
+ add_app_instance(info, hubHandle, env);
+ info++;
+ }
+
+ free(info);
+
+ return 0;
+}
+
+
+int handle_os_message(uint32_t msgType, uint32_t hubHandle,
+ char *msg, int msgLen) {
+ int retVal;
+
+ switch(msgType) {
+ case CONTEXT_HUB_APPS_ENABLE:
+ retVal = 0;
+ break;
+
+ case CONTEXT_HUB_APPS_DISABLE:
+ retVal = 0;
+ break;
+
+ case CONTEXT_HUB_LOAD_APP:
+ retVal = 0;
+ break;
+
+ case CONTEXT_HUB_UNLOAD_APP:
+ retVal = 0;
+ break;
+
+ case CONTEXT_HUB_QUERY_APPS:
+ retVal = handle_query_apps_response(msg, msgLen, hubHandle);
+ break;
+
+ case CONTEXT_HUB_QUERY_MEMORY:
+ retVal = 0;
+ break;
+
+ case CONTEXT_HUB_LOAD_OS:
+ retVal = 0;
+ break;
+
+ default:
+ retVal = -1;
+ break;
+
+ }
+
+ return retVal;
+}
+
+static bool sanity_check_cookie(void *cookie, uint32_t hub_id) {
+ int *ptr = (int *)cookie;
+
+ if (!ptr || *ptr >= db.hubInfo.numHubs) {
+ return false;
+ }
+
+ if (db.hubInfo.hubs[*ptr].hub_id != hub_id) {
+ return false;
+ } else {
+ return true;
+ }
+}
+
+int context_hub_callback(uint32_t hubId,
+ const struct hub_message_t *msg,
void *cookie) {
- int msgHeader[4];
+ int msgHeader[MSG_HEADER_SIZE];
- msgHeader[0] = msg->message_type;
- msgHeader[1] = 0; // TODO : HAL does not have a version field
- msgHeader[2] = hub_id;
+ if (!msg) {
+ return -1;
+ }
- onMessageReceipt(msgHeader, sizeof(msgHeader), (char *)msg->message, msg->message_len); // TODO : Populate this
- return 0;
+ msgHeader[HEADER_FIELD_MSG_TYPE] = msg->message_type;
+
+ if (!sanity_check_cookie(cookie, hubId)) {
+ ALOGW("Incorrect cookie %" PRId32 " for cookie %p! Bailing",
+ hubId, cookie);
+
+ return -1;
+ }
+
+ msgHeader[HEADER_FIELD_HUB_HANDLE] = *(uint32_t*)cookie;
+
+ if (msgHeader[HEADER_FIELD_MSG_TYPE] < CONTEXT_HUB_TYPE_PRIVATE_MSG_BASE &&
+ msgHeader[HEADER_FIELD_MSG_TYPE] != 0 ) {
+ handle_os_message(msgHeader[HEADER_FIELD_MSG_TYPE],
+ msgHeader[HEADER_FIELD_HUB_HANDLE],
+ (char *)msg->message,
+ msg->message_len);
+ } else {
+ onMessageReceipt(msgHeader, sizeof(msgHeader),
+ (char *)msg->message, msg->message_len);
+ }
+
+ return 0;
}
static int init_jni(JNIEnv *env, jobject instance) {
if (env->GetJavaVM(&db.jniInfo.vm) != JNI_OK) {
- return -1;
+ return -1;
}
db.jniInfo.jContextHubService = env->NewGlobalRef(instance);
@@ -167,7 +485,6 @@
db.jniInfo.memoryRegionsClass =
env->FindClass("android/hardware/location/MemoryRegion");
- //TODO :: Add error checking
db.jniInfo.contextHubInfoCtor =
env->GetMethodID(db.jniInfo.contextHubInfoClass, "<init>", "()V");
db.jniInfo.contextHubInfoSetId =
@@ -209,6 +526,9 @@
db.jniInfo.contextHubInfoSetMemoryRegions =
env->GetMethodID(db.jniInfo.contextHubInfoClass,
"setMemoryRegions", "([Landroid/hardware/location/MemoryRegion;)V");
+ db.jniInfo.contextHubInfoSetMaxPacketLenBytes =
+ env->GetMethodID(db.jniInfo.contextHubInfoClass,
+ "setMaxPacketLenBytes", "(I)V");
db.jniInfo.contextHubServiceMsgReceiptCallback =
@@ -218,6 +538,11 @@
env->GetMethodID(db.jniInfo.contextHubInfoClass, "setName",
"(Ljava/lang/String;)V");
+ db.jniInfo.contextHubServiceAddAppInstance =
+ env->GetMethodID(db.jniInfo.contextHubServiceClass,
+ "addAppInstance", "(IIJI)I");
+
+
return 0;
}
@@ -245,20 +570,29 @@
env->CallVoidMethod(jHub, db.jniInfo.contextHubInfoSetPlatformVersion, hub->platform_version);
env->CallVoidMethod(jHub, db.jniInfo.contextHubInfoSetToolchainVersion, hub->toolchain_version);
env->CallVoidMethod(jHub, db.jniInfo.contextHubInfoSetPeakMips, hub->peak_mips);
- env->CallVoidMethod(jHub, db.jniInfo.contextHubInfoSetStoppedPowerDrawMw, hub->stopped_power_draw_mw);
- env->CallVoidMethod(jHub, db.jniInfo.contextHubInfoSetSleepPowerDrawMw, hub->sleep_power_draw_mw);
- env->CallVoidMethod(jHub, db.jniInfo.contextHubInfoSetPeakPowerDrawMw, hub->peak_power_draw_mw);
+ env->CallVoidMethod(jHub, db.jniInfo.contextHubInfoSetStoppedPowerDrawMw,
+ hub->stopped_power_draw_mw);
+ env->CallVoidMethod(jHub, db.jniInfo.contextHubInfoSetSleepPowerDrawMw,
+ hub->sleep_power_draw_mw);
+ env->CallVoidMethod(jHub, db.jniInfo.contextHubInfoSetPeakPowerDrawMw,
+ hub->peak_power_draw_mw);
+ env->CallVoidMethod(jHub, db.jniInfo.contextHubInfoSetMaxPacketLenBytes,
+ hub->max_supported_msg_len);
+
// TODO : jintBuf = env->NewIntArray(hub->num_connected_sensors);
- // TODO : env->SetIntArrayRegion(jintBuf, 0, hub->num_connected_sensors, hub->connected_sensors);
+ // TODO : env->SetIntArrayRegion(jintBuf, 0, hub->num_connected_sensors,
+ // hub->connected_sensors);
jintBuf = env->NewIntArray(array_length(dummyConnectedSensors));
env->SetIntArrayRegion(jintBuf, 0, hub->num_connected_sensors, dummyConnectedSensors);
+ env->CallVoidMethod(jHub, db.jniInfo.contextHubInfoSetSupportedSensors, jintBuf);
// We are not getting the memory regions from the CH Hal - change this when it is available
- jmemBuf = env->NewObjectArray(0, db.jniInfo.memoryRegionsClass, NULL);
+ jmemBuf = env->NewObjectArray(0, db.jniInfo.memoryRegionsClass, nullptr);
// Note the zero size above. We do not need to set any elements
env->CallVoidMethod(jHub, db.jniInfo.contextHubInfoSetMemoryRegions, jmemBuf);
+
return jHub;
}
@@ -267,18 +601,18 @@
jobject hub;
jobjectArray retArray;
- initContextHubService();
-
if (init_jni(env, instance) < 0) {
- return NULL;
+ return nullptr;
}
- // Note : The service is clamping the number of hubs to 1
- db.hubInfo.numHubs = 1;
-
initContextHubService();
- retArray = env->NewObjectArray(db.hubInfo.numHubs, db.jniInfo.contextHubInfoClass, NULL);
+ if (db.hubInfo.numHubs > 1) {
+ ALOGW("Clamping the number of hubs to 1");
+ db.hubInfo.numHubs = 1;
+ }
+
+ retArray = env->NewObjectArray(db.hubInfo.numHubs, db.jniInfo.contextHubInfoClass, nullptr);
for(int i = 0; i < db.hubInfo.numHubs; i++) {
hub = constructJContextHubInfo(env, &db.hubInfo.hubs[i]);
@@ -290,29 +624,41 @@
static jint nativeSendMessage(JNIEnv *env, jobject instance, jintArray header_,
jbyteArray data_) {
- hub_message_t msg;
- hub_app_name_t dest;
- uint8_t os_name[8];
-
- memset(os_name, 0, sizeof(os_name));
+ jint retVal = -1; // Default to failure
jint *header = env->GetIntArrayElements(header_, 0);
- //int numHeaderElements = env->GetArrayLength(header_);
+ unsigned int numHeaderElements = env->GetArrayLength(header_);
jbyte *data = env->GetByteArrayElements(data_, 0);
int dataBufferLength = env->GetArrayLength(data_);
- /* Assume an int - thats all we understand */
- dest.app_name_len = array_length(os_name); // TODO : Check this
- //dest.app_name = &header[1];
- dest.app_name = os_name;
- msg.app = &dest;
+ if (numHeaderElements >= MSG_HEADER_SIZE) {
+ int setAddressSuccess;
+ int hubId;
+ hub_message_t msg;
- msg.message_type = header[3];
- msg.message_len = dataBufferLength;
- msg.message = data;
+ if (header[HEADER_FIELD_APP_INSTANCE] == OS_APP_ID) {
+ setAddressSuccess = (set_os_app_as_destination(&msg, header[HEADER_FIELD_HUB_HANDLE]) == 0);
+ hubId = get_hub_id_for_hub_handle(header[HEADER_FIELD_HUB_HANDLE]);
+ } else {
+ setAddressSuccess = (set_dest_app(&msg, header[HEADER_FIELD_APP_INSTANCE]) == 0);
+ hubId = get_hub_id_for_app_instance(header[HEADER_FIELD_APP_INSTANCE]);
+ }
- jint retVal = db.hubInfo.contextHubModule->send_message(header[0], &msg);
+ if (setAddressSuccess && hubId >= 0) {
+ msg.message_type = header[HEADER_FIELD_MSG_TYPE];
+ msg.message_len = dataBufferLength;
+ msg.message = data;
+ retVal = db.hubInfo.contextHubModule->send_message(hubId, &msg);
+ } else {
+ ALOGD("Could not find app instance %d on hubHandle %d, setAddress %d",
+ header[HEADER_FIELD_APP_INSTANCE],
+ header[HEADER_FIELD_HUB_HANDLE],
+ setAddressSuccess);
+ }
+ } else {
+ ALOGD("Malformed header len");
+ }
env->ReleaseIntArrayElements(header_, header, 0);
env->ReleaseByteArrayElements(data_, data, 0);
diff --git a/core/jni/android_view_RenderNode.cpp b/core/jni/android_view_RenderNode.cpp
index 79b518f..27e2ee8 100644
--- a/core/jni/android_view_RenderNode.cpp
+++ b/core/jni/android_view_RenderNode.cpp
@@ -43,6 +43,54 @@
? (reinterpret_cast<RenderNode*>(renderNodePtr)->setPropertyFieldsDirty(dirtyFlag), true) \
: false)
+static JNIEnv* getenv(JavaVM* vm) {
+ JNIEnv* env;
+ if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
+ LOG_ALWAYS_FATAL("Failed to get JNIEnv for JavaVM: %p", vm);
+ }
+ return env;
+}
+
+static jmethodID gOnRenderNodeDetached;
+
+class RenderNodeContext : public VirtualLightRefBase {
+public:
+ RenderNodeContext(JNIEnv* env, jobject jobjRef) {
+ env->GetJavaVM(&mVm);
+ // This holds a weak ref because otherwise there's a cyclic global ref
+ // with this holding a strong global ref to the view which holds
+ // a strong ref to RenderNode which holds a strong ref to this.
+ mWeakRef = env->NewWeakGlobalRef(jobjRef);
+ }
+
+ virtual ~RenderNodeContext() {
+ JNIEnv* env = getenv(mVm);
+ env->DeleteWeakGlobalRef(mWeakRef);
+ }
+
+ jobject acquireLocalRef(JNIEnv* env) {
+ return env->NewLocalRef(mWeakRef);
+ }
+
+private:
+ JavaVM* mVm;
+ jweak mWeakRef;
+};
+
+// Called by ThreadedRenderer's JNI layer
+void onRenderNodeRemoved(JNIEnv* env, RenderNode* node) {
+ auto context = reinterpret_cast<RenderNodeContext*>(node->getUserContext());
+ if (!context) return;
+ jobject jnode = context->acquireLocalRef(env);
+ if (!jnode) {
+ // The owning node has been GC'd, release the context
+ node->setUserContext(nullptr);
+ return;
+ }
+ env->CallVoidMethod(jnode, gOnRenderNodeDetached);
+ env->DeleteLocalRef(jnode);
+}
+
// ----------------------------------------------------------------------------
// DisplayList view properties
// ----------------------------------------------------------------------------
@@ -59,7 +107,8 @@
return renderNode->getDebugSize();
}
-static jlong android_view_RenderNode_create(JNIEnv* env, jobject clazz, jstring name) {
+static jlong android_view_RenderNode_create(JNIEnv* env, jobject thiz,
+ jstring name) {
RenderNode* renderNode = new RenderNode();
renderNode->incStrong(0);
if (name != NULL) {
@@ -67,6 +116,7 @@
renderNode->setName(textArray);
env->ReleaseStringUTFChars(name, textArray);
}
+ renderNode->setUserContext(new RenderNodeContext(env, thiz));
return reinterpret_cast<jlong>(renderNode);
}
@@ -627,6 +677,9 @@
jclass clazz = FindClassOrDie(env, "android/view/SurfaceView");
gSurfaceViewPositionUpdateMethod = GetMethodIDOrDie(env, clazz,
"updateWindowPositionRT", "(JIIII)V");
+ clazz = FindClassOrDie(env, "android/view/RenderNode");
+ gOnRenderNodeDetached = GetMethodIDOrDie(env, clazz,
+ "onRenderNodeDetached", "()V");
return RegisterMethodsOrDie(env, kClassPathName, gMethods, NELEM(gMethods));
}
diff --git a/core/jni/android_view_ThreadedRenderer.cpp b/core/jni/android_view_ThreadedRenderer.cpp
index 07868c5..8019326 100644
--- a/core/jni/android_view_ThreadedRenderer.cpp
+++ b/core/jni/android_view_ThreadedRenderer.cpp
@@ -120,7 +120,13 @@
std::string mMessage;
};
-class RootRenderNode : public RenderNode, ErrorHandler {
+// TODO: Clean this up, it's a bit odd to need to call over to
+// rendernode's jni layer. Probably means RootRenderNode should be pulled
+// into HWUI with appropriate callbacks for the various JNI hooks so
+// that RenderNode's JNI layer can handle its own thing
+void onRenderNodeRemoved(JNIEnv* env, RenderNode* node);
+
+class RootRenderNode : public RenderNode, ErrorHandler, TreeObserver {
public:
RootRenderNode(JNIEnv* env) : RenderNode() {
mLooper = Looper::getForThread();
@@ -131,12 +137,15 @@
virtual ~RootRenderNode() {}
- virtual void onError(const std::string& message) {
+ virtual void onError(const std::string& message) override {
mLooper->sendMessage(new RenderingException(mVm, message), 0);
}
- virtual void prepareTree(TreeInfo& info) {
+ virtual void prepareTree(TreeInfo& info) override {
info.errorHandler = this;
+ if (info.mode == TreeInfo::MODE_FULL) {
+ info.observer = this;
+ }
// TODO: This is hacky
info.windowInsetLeft = -stagingProperties().getLeft();
info.windowInsetTop = -stagingProperties().getTop();
@@ -145,7 +154,8 @@
info.updateWindowPositions = false;
info.windowInsetLeft = 0;
info.windowInsetTop = 0;
- info.errorHandler = NULL;
+ info.errorHandler = nullptr;
+ info.observer = nullptr;
}
void sendMessage(const sp<MessageHandler>& handler) {
@@ -171,10 +181,27 @@
mPendingAnimatingRenderNodes.clear();
}
+ virtual void onMaybeRemovedFromTree(RenderNode* node) override {
+ mMaybeRemovedNodes.insert(sp<RenderNode>(node));
+ }
+
+ void processMaybeRemovedNodes(JNIEnv* env) {
+ // We can safely access mMaybeRemovedNodes here because
+ // we will only modify it in prepareTree calls that are
+ // MODE_FULL
+
+ for (auto& node : mMaybeRemovedNodes) {
+ if (node->hasParents()) continue;
+ onRenderNodeRemoved(env, node.get());
+ }
+ mMaybeRemovedNodes.clear();
+ }
+
private:
sp<Looper> mLooper;
JavaVM* mVm;
std::vector< sp<RenderNode> > mPendingAnimatingRenderNodes;
+ std::set< sp<RenderNode> > mMaybeRemovedNodes;
};
class AnimationContextBridge : public AnimationContext {
@@ -473,13 +500,16 @@
}
static int android_view_ThreadedRenderer_syncAndDrawFrame(JNIEnv* env, jobject clazz,
- jlong proxyPtr, jlongArray frameInfo, jint frameInfoSize) {
+ jlong proxyPtr, jlongArray frameInfo, jint frameInfoSize, jlong rootNodePtr) {
LOG_ALWAYS_FATAL_IF(frameInfoSize != UI_THREAD_FRAME_INFO_SIZE,
"Mismatched size expectations, given %d expected %d",
frameInfoSize, UI_THREAD_FRAME_INFO_SIZE);
RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
+ RootRenderNode* rootRenderNode = reinterpret_cast<RootRenderNode*>(rootNodePtr);
env->GetLongArrayRegion(frameInfo, 0, frameInfoSize, proxy->frameInfo());
- return proxy->syncAndDrawFrame();
+ int ret = proxy->syncAndDrawFrame();
+ rootRenderNode->processMaybeRemovedNodes(env);
+ return ret;
}
static void android_view_ThreadedRenderer_destroy(JNIEnv* env, jobject clazz,
@@ -706,7 +736,7 @@
{ "nSetup", "(JIIFII)V", (void*) android_view_ThreadedRenderer_setup },
{ "nSetLightCenter", "(JFFF)V", (void*) android_view_ThreadedRenderer_setLightCenter },
{ "nSetOpaque", "(JZ)V", (void*) android_view_ThreadedRenderer_setOpaque },
- { "nSyncAndDrawFrame", "(J[JI)I", (void*) android_view_ThreadedRenderer_syncAndDrawFrame },
+ { "nSyncAndDrawFrame", "(J[JIJ)I", (void*) android_view_ThreadedRenderer_syncAndDrawFrame },
{ "nDestroy", "(JJ)V", (void*) android_view_ThreadedRenderer_destroy },
{ "nRegisterAnimatingRenderNode", "(JJ)V", (void*) android_view_ThreadedRenderer_registerAnimatingRenderNode },
{ "nInvokeFunctor", "(JZ)V", (void*) android_view_ThreadedRenderer_invokeFunctor },
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 8abb7e2..9219e81 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -348,6 +348,8 @@
<protected-broadcast android:name="android.app.action.DEVICE_OWNER_CHANGED" />
<protected-broadcast android:name="android.intent.action.MANAGED_PROFILE_AVAILABILITY_CHANGED" />
+ <protected-broadcast android:name="android.intent.action.MANAGED_PROFILE_AVAILABLE" />
+ <protected-broadcast android:name="android.intent.action.MANAGED_PROFILE_UNAVAILABLE" />
<!-- Added in N -->
<protected-broadcast android:name="android.intent.action.ANR" />
@@ -845,14 +847,14 @@
-->
<permission android:name="android.permission.ACCESS_UCE_PRESENCE_SERVICE"
android:permissionGroup="android.permission-group.PHONE"
- android:protectionLevel="dangerous"/>
+ android:protectionLevel="signatureOrSystem"/>
<!-- @hide Allows an application to Access UCE-OPTIONS.
<p>Protection level: dangerous
-->
<permission android:name="android.permission.ACCESS_UCE_OPTIONS_SERVICE"
android:permissionGroup="android.permission-group.PHONE"
- android:protectionLevel="dangerous"/>
+ android:protectionLevel="signatureOrSystem"/>
@@ -2004,6 +2006,11 @@
<permission android:name="android.permission.GET_ACCOUNTS_PRIVILEGED"
android:protectionLevel="signature|privileged" />
+ <!-- @SystemApi Allows but does not guarantee access to user passwords at the conclusion of add
+ account -->
+ <permission android:name="android.permission.GET_PASSWORD_PRIVILEGED"
+ android:protectionLevel="signature|privileged" />
+
<!-- @SystemApi Allows applications to RW to diagnostic resources.
<p>Not for use by third-party applications. -->
<permission android:name="android.permission.DIAGNOSTIC"
@@ -2172,6 +2179,15 @@
<permission android:name="android.permission.BIND_PRINT_SERVICE"
android:protectionLevel="signature" />
+ <!-- Must be required by a {@link android.printservice.recommendation.RecommendationService},
+ to ensure that only the system can bind to it.
+ @hide
+ @SystemApi
+ <p>Protection level: signature
+ -->
+ <permission android:name="android.permission.BIND_PRINT_RECOMMENDATION_SERVICE"
+ android:protectionLevel="signature" />
+
<!-- Must be required by a {@link android.nfc.cardemulation.HostApduService}
or {@link android.nfc.cardemulation.OffHostApduService} to ensure that only
the system can bind to it.
@@ -2975,6 +2991,11 @@
<permission android:name="android.permission.BIND_VR_LISTENER_SERVICE"
android:protectionLevel="signature" />
+ <!-- Allows an application to whitelist tasks during lock task mode
+ @hide <p>Not for use by third-party applications.</p> -->
+ <permission android:name="android.permission.UPDATE_LOCK_TASK_PACKAGES"
+ android:protectionLevel="signature|setup" />
+
<application android:process="system"
android:persistent="true"
android:hasCode="false"
@@ -2984,7 +3005,7 @@
android:killAfterRestore="false"
android:icon="@drawable/ic_launcher_android"
android:supportsRtl="true"
- android:theme="@style/Theme.Material.DayNight.DarkActionBar"
+ android:theme="@style/Theme.Material.Light.DarkActionBar"
android:defaultToDeviceProtectedStorage="true"
android:directBootAware="true">
<activity android:name="com.android.internal.app.ChooserActivity"
@@ -3020,7 +3041,7 @@
android:label="@string/managed_profile_label">
</activity-alias>
<activity android:name="com.android.internal.app.HeavyWeightSwitcherActivity"
- android:theme="@style/Theme.Material.DayNight.Dialog"
+ android:theme="@style/Theme.Material.Light.Dialog"
android:label="@string/heavy_weight_switcher_title"
android:finishOnCloseSystemDialogs="true"
android:excludeFromRecents="true"
@@ -3053,7 +3074,7 @@
<activity android:name="android.accounts.ChooseAccountActivity"
android:excludeFromRecents="true"
android:exported="true"
- android:theme="@style/Theme.Material.DayNight.Dialog"
+ android:theme="@style/Theme.Material.Light.Dialog"
android:label="@string/choose_account_label"
android:process=":ui">
</activity>
@@ -3061,14 +3082,14 @@
<activity android:name="android.accounts.ChooseTypeAndAccountActivity"
android:excludeFromRecents="true"
android:exported="true"
- android:theme="@style/Theme.Material.DayNight.Dialog"
+ android:theme="@style/Theme.Material.Light.Dialog"
android:label="@string/choose_account_label"
android:process=":ui">
</activity>
<activity android:name="android.accounts.ChooseAccountTypeActivity"
android:excludeFromRecents="true"
- android:theme="@style/Theme.Material.DayNight.Dialog"
+ android:theme="@style/Theme.Material.Light.Dialog"
android:label="@string/choose_account_label"
android:process=":ui">
</activity>
@@ -3076,19 +3097,19 @@
<activity android:name="android.accounts.CantAddAccountActivity"
android:excludeFromRecents="true"
android:exported="true"
- android:theme="@style/Theme.Material.DayNight.Dialog.NoActionBar"
+ android:theme="@style/Theme.Material.Light.Dialog.NoActionBar"
android:process=":ui">
</activity>
<activity android:name="android.accounts.GrantCredentialsPermissionActivity"
android:excludeFromRecents="true"
android:exported="true"
- android:theme="@style/Theme.Material.DayNight.DialogWhenLarge"
+ android:theme="@style/Theme.Material.Light.DialogWhenLarge"
android:process=":ui">
</activity>
<activity android:name="android.content.SyncActivityTooManyDeletes"
- android:theme="@style/Theme.Material.DayNight.Dialog"
+ android:theme="@style/Theme.Material.Light.Dialog"
android:label="@string/sync_too_many_deletes"
android:process=":ui">
</activity>
@@ -3108,7 +3129,7 @@
</activity>
<activity android:name="com.android.internal.app.NetInitiatedActivity"
- android:theme="@style/Theme.Material.DayNight.Dialog.Alert"
+ android:theme="@style/Theme.Material.Light.Dialog.Alert"
android:excludeFromRecents="true"
android:process=":ui">
</activity>
@@ -3129,7 +3150,7 @@
<activity android:name="com.android.internal.app.ConfirmUserCreationActivity"
android:excludeFromRecents="true"
android:process=":ui"
- android:theme="@style/Theme.Material.DayNight.Dialog.Alert">
+ android:theme="@style/Theme.Material.Light.Dialog.Alert">
<intent-filter android:priority="1000">
<action android:name="android.os.action.CREATE_USER" />
<category android:name="android.intent.category.DEFAULT" />
@@ -3137,7 +3158,7 @@
</activity>
<activity android:name="com.android.internal.app.UnlaunchableAppActivity"
- android:theme="@style/Theme.Material.DayNight.Dialog.Alert"
+ android:theme="@style/Theme.Material.Light.Dialog.Alert"
android:excludeFromRecents="true"
android:process=":ui">
</activity>
diff --git a/core/res/res/anim/slide_in_micro.xml b/core/res/res/anim/slide_in_enter_micro.xml
similarity index 67%
rename from core/res/res/anim/slide_in_micro.xml
rename to core/res/res/anim/slide_in_enter_micro.xml
index 6320e80..14a5290 100644
--- a/core/res/res/anim/slide_in_micro.xml
+++ b/core/res/res/anim/slide_in_enter_micro.xml
@@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
-/* //device/apps/common/res/anim/slide_in_micro.xml
**
** Copyright 2014, The Android Open Source Project
**
@@ -18,10 +17,13 @@
*/
-->
-<set xmlns:android="http://schemas.android.com/apk/res/android">
- <translate android:fromXDelta="100%p" android:toXDelta="0"
- android:duration="@android:integer/config_mediumAnimTime"/>
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+ android:zAdjustment="top">
+ <translate android:fromYDelta="5%p" android:toXDelta="0"
+ android:duration="417"
+ android:interpolator="@android:interpolator/launch_task_micro_ydelta" />
<alpha android:fromAlpha="0.0" android:toAlpha="1.0"
android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
- android:duration="@android:integer/config_mediumAnimTime" />
+ android:duration="150"
+ android:interpolator="@android:interpolator/launch_task_micro_alpha" />
</set>
diff --git a/core/java/com/android/internal/app/ProcessStats.aidl b/core/res/res/anim/slide_in_exit_micro.xml
similarity index 60%
copy from core/java/com/android/internal/app/ProcessStats.aidl
copy to core/res/res/anim/slide_in_exit_micro.xml
index 48b1f85..f0d8c0b 100644
--- a/core/java/com/android/internal/app/ProcessStats.aidl
+++ b/core/res/res/anim/slide_in_exit_micro.xml
@@ -1,5 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
/*
-** Copyright 2013, The Android Open Source Project
+** 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.
@@ -13,7 +15,10 @@
** See the License for the specific language governing permissions and
** limitations under the License.
*/
+-->
-package com.android.internal.app;
-
-parcelable ProcessStats;
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+ android:detachWallpaper="true" android:shareInterpolator="false" android:zAdjustment="normal">
+ <alpha android:fromAlpha="1.0" android:toAlpha="1.0"
+ android:duration="417" />
+</set>
diff --git a/core/res/res/anim/slide_out_micro.xml b/core/res/res/anim/slide_out_micro.xml
index 4cb6df0..c647093 100644
--- a/core/res/res/anim/slide_out_micro.xml
+++ b/core/res/res/anim/slide_out_micro.xml
@@ -18,10 +18,13 @@
*/
-->
-<set xmlns:android="http://schemas.android.com/apk/res/android">
- <translate android:fromXDelta="0" android:toXDelta="100%p"
- android:duration="@android:integer/config_mediumAnimTime"/>
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+ android:zAdjustment="top">
+ <translate android:fromYDelta="0" android:toYDelta="5%p"
+ android:duration="250"
+ android:interpolator="@android:interpolator/fast_out_slow_in"/>
<alpha android:fromAlpha="1.0" android:toAlpha="0.0"
android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
- android:duration="@android:integer/config_mediumAnimTime" />
+ android:startOffset="100" android:duration="150"
+ android:interpolator="@android:interpolator/fast_out_slow_in" />
</set>
diff --git a/core/java/com/android/internal/app/ProcessStats.aidl b/core/res/res/interpolator/launch_task_micro_alpha.xml
similarity index 61%
copy from core/java/com/android/internal/app/ProcessStats.aidl
copy to core/res/res/interpolator/launch_task_micro_alpha.xml
index 48b1f85..41b79b5 100644
--- a/core/java/com/android/internal/app/ProcessStats.aidl
+++ b/core/res/res/interpolator/launch_task_micro_alpha.xml
@@ -1,5 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
/*
-** Copyright 2013, The Android Open Source Project
+** Copyright 2014, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
@@ -13,7 +15,10 @@
** See the License for the specific language governing permissions and
** limitations under the License.
*/
+-->
-package com.android.internal.app;
-
-parcelable ProcessStats;
+<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android"
+ android:controlX1="0"
+ android:controlY1="0"
+ android:controlX2="0.7"
+ android:controlY2="1" />
diff --git a/core/java/com/android/internal/app/ProcessStats.aidl b/core/res/res/interpolator/launch_task_micro_ydelta.xml
similarity index 61%
copy from core/java/com/android/internal/app/ProcessStats.aidl
copy to core/res/res/interpolator/launch_task_micro_ydelta.xml
index 48b1f85..acac761 100644
--- a/core/java/com/android/internal/app/ProcessStats.aidl
+++ b/core/res/res/interpolator/launch_task_micro_ydelta.xml
@@ -1,5 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
/*
-** Copyright 2013, The Android Open Source Project
+** Copyright 2014, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
@@ -13,7 +15,10 @@
** See the License for the specific language governing permissions and
** limitations under the License.
*/
+-->
-package com.android.internal.app;
-
-parcelable ProcessStats;
+<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android"
+ android:controlX1="0"
+ android:controlY1="0"
+ android:controlX2="0.4"
+ android:controlY2="1" />
diff --git a/core/res/res/layout-w600dp/preference_list_content_single.xml b/core/res/res/layout-sw600dp/preference_list_content_single.xml
similarity index 88%
rename from core/res/res/layout-w600dp/preference_list_content_single.xml
rename to core/res/res/layout-sw600dp/preference_list_content_single.xml
index d2fa5b9..88b1aa8 100644
--- a/core/res/res/layout-w600dp/preference_list_content_single.xml
+++ b/core/res/res/layout-sw600dp/preference_list_content_single.xml
@@ -33,20 +33,22 @@
style="?attr/preferencePanelStyle"
android:orientation="vertical"
android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:paddingStart="32dip"
- android:paddingEnd="32dip"
- android:paddingTop="32dip"
- android:paddingBottom="32dip" >
+ android:layout_height="match_parent">
- <ListView android:id="@android:id/list"
+ <ListView
+ android:id="@android:id/list"
android:layout_width="match_parent"
android:layout_height="0px"
android:layout_weight="1"
android:drawSelectorOnTop="false"
android:cacheColorHint="@android:color/transparent"
android:listPreferredItemHeight="48dp"
- android:scrollbarAlwaysDrawVerticalTrack="true" />
+ android:scrollbarAlwaysDrawVerticalTrack="true"
+ android:paddingStart="32dip"
+ android:paddingEnd="32dip"
+ android:paddingTop="32dip"
+ android:paddingBottom="32dip"
+ android:clipToPadding="false"/>
<FrameLayout android:id="@+id/list_footer"
android:layout_width="match_parent"
diff --git a/core/res/res/layout/alert_dialog_material.xml b/core/res/res/layout/alert_dialog_material.xml
index 9f50937..6d33de6 100644
--- a/core/res/res/layout/alert_dialog_material.xml
+++ b/core/res/res/layout/alert_dialog_material.xml
@@ -34,7 +34,6 @@
android:id="@+id/scrollView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:paddingTop="@dimen/dialog_padding_top_material"
android:clipToPadding="false">
<LinearLayout
@@ -42,6 +41,12 @@
android:layout_height="wrap_content"
android:orientation="vertical">
+ <Space
+ android:id="@+id/textSpacerNoTitle"
+ android:visibility="gone"
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/dialog_padding_top_material" />
+
<TextView
android:id="@+id/message"
android:layout_width="match_parent"
@@ -53,7 +58,7 @@
<Space
android:id="@+id/textSpacerNoButtons"
android:visibility="gone"
- android:layout_width="0dp"
+ android:layout_width="match_parent"
android:layout_height="@dimen/dialog_padding_top_material" />
</LinearLayout>
</ScrollView>
diff --git a/core/res/res/layout/alert_dialog_title_material.xml b/core/res/res/layout/alert_dialog_title_material.xml
index 738a637..eef9585 100644
--- a/core/res/res/layout/alert_dialog_title_material.xml
+++ b/core/res/res/layout/alert_dialog_title_material.xml
@@ -21,6 +21,8 @@
android:layout_height="wrap_content"
android:orientation="vertical">
+ <!-- If the client uses a customTitle, it will be added here. -->
+
<LinearLayout
android:id="@+id/title_template"
android:layout_width="match_parent"
@@ -49,5 +51,9 @@
style="?attr/windowTitleStyle" />
</LinearLayout>
- <!-- If the client uses a customTitle, it will be added here. -->
+ <Space
+ android:id="@+id/titleDividerNoCustom"
+ android:visibility="gone"
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/dialog_title_divider_material" />
</LinearLayout>
diff --git a/core/res/res/layout/app_anr_dialog.xml b/core/res/res/layout/app_anr_dialog.xml
index 8bef116..5ad0f4c 100644
--- a/core/res/res/layout/app_anr_dialog.xml
+++ b/core/res/res/layout/app_anr_dialog.xml
@@ -19,7 +19,7 @@
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingTop="@dimen/aerr_padding_list_top"
- android:paddingBottom="@dimen/dialog_list_padding_vertical_material">
+ android:paddingBottom="@dimen/aerr_padding_list_bottom">
<Button
android:id="@+id/aerr_close"
diff --git a/core/res/res/layout/app_error_dialog.xml b/core/res/res/layout/app_error_dialog.xml
index b9531f4..7147ea2 100644
--- a/core/res/res/layout/app_error_dialog.xml
+++ b/core/res/res/layout/app_error_dialog.xml
@@ -22,7 +22,7 @@
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingTop="@dimen/aerr_padding_list_top"
- android:paddingBottom="@dimen/dialog_list_padding_vertical_material">
+ android:paddingBottom="@dimen/aerr_padding_list_bottom">
<Button
diff --git a/core/res/res/layout/chooser_grid.xml b/core/res/res/layout/chooser_grid.xml
index 41726fb..d12c8ba 100644
--- a/core/res/res/layout/chooser_grid.xml
+++ b/core/res/res/layout/chooser_grid.xml
@@ -25,63 +25,48 @@
android:maxCollapsedHeightSmall="56dp"
android:id="@id/contentPanel">
- <LinearLayout
+ <RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alwaysShow="true"
android:elevation="8dp"
android:paddingStart="16dp"
android:background="@color/white" >
+ <TextView android:id="@+id/profile_button"
+ android:layout_width="wrap_content"
+ android:layout_height="48dp"
+ android:layout_marginEnd="8dp"
+ android:paddingStart="8dp"
+ android:paddingEnd="8dp"
+ android:visibility="gone"
+ style="?attr/borderlessButtonStyle"
+ android:textAppearance="?attr/textAppearanceButton"
+ android:textColor="@color/material_deep_teal_500"
+ android:gravity="center_vertical"
+ android:layout_alignParentTop="true"
+ android:layout_alignParentRight="true"
+ android:singleLine="true"/>
<ImageView android:id="@+id/title_icon"
android:layout_width="24dp"
android:layout_height="24dp"
- android:layout_gravity="start|center_vertical"
android:layout_marginEnd="16dp"
android:visibility="gone"
- android:scaleType="fitCenter" />
+ android:scaleType="fitCenter"
+ android:layout_below="@id/profile_button"
+ android:layout_alignParentLeft="true"
+ />
<TextView android:id="@+id/title"
- android:layout_width="0dp"
android:layout_height="wrap_content"
- android:layout_weight="1"
+ android:layout_width="wrap_content"
android:textAppearance="?attr/textAppearanceMedium"
android:textSize="14sp"
android:gravity="start|center_vertical"
android:paddingEnd="?attr/dialogPreferredPadding"
android:paddingTop="12dp"
- android:paddingBottom="12dp" />
- <LinearLayout android:id="@+id/profile_button"
- android:layout_width="wrap_content"
- android:layout_height="48dp"
- android:layout_marginTop="4dp"
- android:layout_marginEnd="4dp"
- android:paddingStart="8dp"
- android:paddingEnd="8dp"
- android:paddingTop="4dp"
- android:paddingBottom="4dp"
- android:focusable="true"
- android:visibility="gone"
- style="?attr/borderlessButtonStyle">
- <ImageView android:id="@+id/icon"
- android:layout_width="24dp"
- android:layout_height="24dp"
- android:layout_gravity="start|center_vertical"
- android:layout_marginStart="4dp"
- android:layout_marginEnd="16dp"
- android:layout_marginTop="12dp"
- android:layout_marginBottom="12dp"
- android:scaleType="fitCenter" />
- <TextView android:id="@id/text1"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="start|center_vertical"
- android:layout_marginEnd="16dp"
- android:textAppearance="?attr/textAppearanceButton"
- android:textColor="?attr/textColorPrimary"
- android:minLines="1"
- android:maxLines="1"
- android:ellipsize="marquee" />
- </LinearLayout>
- </LinearLayout>
+ android:paddingBottom="12dp"
+ android:layout_below="@id/profile_button"
+ android:layout_toRightOf="@id/title_icon"/>
+ </RelativeLayout>
<ListView
android:layout_width="match_parent"
diff --git a/core/res/res/layout/notification_material_action_list.xml b/core/res/res/layout/notification_material_action_list.xml
index 30b5a79..ac37c4a 100644
--- a/core/res/res/layout/notification_material_action_list.xml
+++ b/core/res/res/layout/notification_material_action_list.xml
@@ -17,9 +17,7 @@
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/actions_container"
android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginStart="-16dp"
- android:layout_marginEnd="-16dp">
+ android:layout_height="wrap_content">
<LinearLayout
android:id="@+id/actions"
android:layout_width="match_parent"
diff --git a/core/res/res/layout/notification_template_material_big_base.xml b/core/res/res/layout/notification_template_material_big_base.xml
index d53fb5f..c54fa18 100644
--- a/core/res/res/layout/notification_template_material_big_base.xml
+++ b/core/res/res/layout/notification_template_material_big_base.xml
@@ -60,9 +60,5 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
/>
- <include
- layout="@layout/notification_material_action_list"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- />
+ <include layout="@layout/notification_material_action_list" />
</LinearLayout>
diff --git a/core/res/res/layout/notification_template_material_big_picture.xml b/core/res/res/layout/notification_template_material_big_picture.xml
index 50aec6b..d87b9d9 100644
--- a/core/res/res/layout/notification_template_material_big_picture.xml
+++ b/core/res/res/layout/notification_template_material_big_picture.xml
@@ -27,8 +27,6 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="top"
- android:paddingStart="@dimen/notification_content_margin_start"
- android:paddingEnd="@dimen/notification_content_margin_end"
android:layout_marginTop="@dimen/notification_content_margin_top"
android:clipToPadding="false"
android:orientation="vertical"
@@ -37,6 +35,8 @@
android:id="@+id/notification_main_column"
android:layout_width="match_parent"
android:layout_height="wrap_content"
+ android:layout_marginStart="@dimen/notification_content_margin_start"
+ android:layout_marginEnd="@dimen/notification_content_margin_end"
android:orientation="vertical">
<include layout="@layout/notification_template_part_line1"/>
<include layout="@layout/notification_template_progress"/>
@@ -50,14 +50,15 @@
android:layout_weight="1"
android:layout_marginTop="13dp"
android:layout_marginBottom="16dp"
+ android:layout_marginStart="@dimen/notification_content_margin_start"
+ android:layout_marginEnd="@dimen/notification_content_margin_end"
android:scaleType="centerCrop"
/>
+
<ViewStub android:layout="@layout/notification_material_reply_text"
android:id="@+id/notification_material_reply_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_marginStart="-16dp"
- android:layout_marginEnd="-16dp"
/>
<include layout="@layout/notification_material_action_list" />
</LinearLayout>
diff --git a/core/res/res/layout/notification_template_material_big_text.xml b/core/res/res/layout/notification_template_material_big_text.xml
index fdfefe1..3638b20 100644
--- a/core/res/res/layout/notification_template_material_big_text.xml
+++ b/core/res/res/layout/notification_template_material_big_text.xml
@@ -22,38 +22,45 @@
android:tag="bigText"
>
<include layout="@layout/notification_template_header" />
+
<LinearLayout
- android:id="@+id/notification_main_column"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_gravity="top"
- android:paddingStart="@dimen/notification_content_margin_start"
- android:paddingEnd="@dimen/notification_content_margin_end"
- android:layout_marginTop="@dimen/notification_content_margin_top"
- android:clipToPadding="false"
- android:minHeight="@dimen/notification_min_content_height"
- android:orientation="vertical"
- >
- <include layout="@layout/notification_template_part_line1" />
- <include layout="@layout/notification_template_progress" />
- <com.android.internal.widget.ImageFloatingTextView android:id="@+id/big_text"
android:layout_width="match_parent"
- android:layout_height="0dp"
- android:layout_marginTop="0.5dp"
- android:paddingBottom="@dimen/notification_content_margin_bottom"
- android:textAppearance="@style/TextAppearance.Material.Notification"
- android:singleLine="false"
- android:layout_weight="1"
- android:gravity="top"
- android:visibility="gone"
- />
+ android:layout_height="match_parent"
+ android:layout_gravity="top"
+ android:layout_marginTop="@dimen/notification_content_margin_top"
+ android:clipToPadding="false"
+ android:orientation="vertical">
+
+ <LinearLayout
+ android:id="@+id/notification_main_column"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="top"
+ android:paddingStart="@dimen/notification_content_margin_start"
+ android:paddingEnd="@dimen/notification_content_margin_end"
+ android:clipToPadding="false"
+ android:minHeight="@dimen/notification_min_content_height"
+ android:orientation="vertical"
+ >
+ <include layout="@layout/notification_template_part_line1" />
+ <include layout="@layout/notification_template_progress" />
+ <com.android.internal.widget.ImageFloatingTextView android:id="@+id/big_text"
+ android:layout_width="match_parent"
+ android:layout_height="0dp"
+ android:layout_marginTop="0.5dp"
+ android:paddingBottom="@dimen/notification_content_margin_bottom"
+ android:textAppearance="@style/TextAppearance.Material.Notification"
+ android:singleLine="false"
+ android:layout_weight="1"
+ android:gravity="top"
+ android:visibility="gone"
+ />
+ </LinearLayout>
+
<ViewStub android:layout="@layout/notification_material_reply_text"
android:id="@+id/notification_material_reply_container"
android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginStart="-16dp"
- android:layout_marginEnd="-16dp"
- />
+ android:layout_height="wrap_content" />
<include layout="@layout/notification_material_action_list" />
</LinearLayout>
<include layout="@layout/notification_template_right_icon" />
diff --git a/core/res/res/layout/notification_template_material_inbox.xml b/core/res/res/layout/notification_template_material_inbox.xml
index 86902db..ce9acda 100644
--- a/core/res/res/layout/notification_template_material_inbox.xml
+++ b/core/res/res/layout/notification_template_material_inbox.xml
@@ -23,87 +23,99 @@
>
<include layout="@layout/notification_template_header" />
<LinearLayout
- android:id="@+id/notification_main_column"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_gravity="top"
- android:paddingStart="@dimen/notification_content_margin_start"
- android:paddingEnd="@dimen/notification_content_margin_end"
- android:layout_marginTop="@dimen/notification_content_margin_top"
- android:minHeight="@dimen/notification_min_content_height"
- android:clipToPadding="false"
- android:orientation="vertical"
- >
- <include layout="@layout/notification_template_part_line1"
android:layout_width="match_parent"
- android:layout_height="wrap_content" />
- <include layout="@layout/notification_template_progress"
+ android:layout_height="match_parent"
+ android:layout_gravity="top"
+ android:layout_marginTop="@dimen/notification_content_margin_top"
+ android:clipToPadding="false"
+ android:orientation="vertical">
+
+ <LinearLayout
+ android:id="@+id/notification_main_column"
android:layout_width="match_parent"
- android:layout_height="15dp"
- android:layout_marginTop="4dp"/>
- <TextView android:id="@+id/inbox_text0"
- android:textAppearance="@style/TextAppearance.Material.Notification"
- android:layout_width="match_parent"
- android:layout_height="0dp"
- android:singleLine="true"
- android:ellipsize="end"
- android:visibility="gone"
- android:layout_weight="1"
- />
- <TextView android:id="@+id/inbox_text1"
- android:textAppearance="@style/TextAppearance.Material.Notification"
- android:layout_width="match_parent"
- android:layout_height="0dp"
- android:singleLine="true"
- android:ellipsize="end"
- android:visibility="gone"
- android:layout_weight="1"
- />
- <TextView android:id="@+id/inbox_text2"
- android:textAppearance="@style/TextAppearance.Material.Notification"
- android:layout_width="match_parent"
- android:layout_height="0dp"
- android:singleLine="true"
- android:ellipsize="end"
- android:visibility="gone"
- android:layout_weight="1"
- />
- <TextView android:id="@+id/inbox_text3"
- android:textAppearance="@style/TextAppearance.Material.Notification"
- android:layout_width="match_parent"
- android:layout_height="0dp"
- android:singleLine="true"
- android:ellipsize="end"
- android:visibility="gone"
- android:layout_weight="1"
- />
- <TextView android:id="@+id/inbox_text4"
- android:textAppearance="@style/TextAppearance.Material.Notification"
- android:layout_width="match_parent"
- android:layout_height="0dp"
- android:singleLine="true"
- android:ellipsize="end"
- android:visibility="gone"
- android:layout_weight="1"
- />
- <TextView android:id="@+id/inbox_text5"
- android:textAppearance="@style/TextAppearance.Material.Notification"
- android:layout_width="match_parent"
- android:layout_height="0dp"
- android:singleLine="true"
- android:ellipsize="end"
- android:visibility="gone"
- android:layout_weight="1"
- />
- <TextView android:id="@+id/inbox_text6"
- android:textAppearance="@style/TextAppearance.Material.Notification"
- android:layout_width="match_parent"
- android:layout_height="0dp"
- android:singleLine="true"
- android:ellipsize="end"
- android:visibility="gone"
- android:layout_weight="1"
- />
+ android:layout_height="wrap_content"
+ android:layout_gravity="top"
+ android:paddingStart="@dimen/notification_content_margin_start"
+ android:paddingEnd="@dimen/notification_content_margin_end"
+ android:minHeight="@dimen/notification_min_content_height"
+ android:clipToPadding="false"
+ android:orientation="vertical"
+ >
+ <include layout="@layout/notification_template_part_line1"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content" />
+ <include layout="@layout/notification_template_progress"
+ android:layout_width="match_parent"
+ android:layout_height="15dp"
+ android:layout_marginTop="4dp"/>
+ <TextView android:id="@+id/inbox_text0"
+ android:textAppearance="@style/TextAppearance.Material.Notification"
+ android:layout_width="match_parent"
+ android:layout_height="0dp"
+ android:singleLine="true"
+ android:ellipsize="end"
+ android:visibility="gone"
+ android:layout_weight="1"
+ />
+ <TextView android:id="@+id/inbox_text1"
+ android:textAppearance="@style/TextAppearance.Material.Notification"
+ android:layout_width="match_parent"
+ android:layout_height="0dp"
+ android:singleLine="true"
+ android:ellipsize="end"
+ android:visibility="gone"
+ android:layout_weight="1"
+ />
+ <TextView android:id="@+id/inbox_text2"
+ android:textAppearance="@style/TextAppearance.Material.Notification"
+ android:layout_width="match_parent"
+ android:layout_height="0dp"
+ android:singleLine="true"
+ android:ellipsize="end"
+ android:visibility="gone"
+ android:layout_weight="1"
+ />
+ <TextView android:id="@+id/inbox_text3"
+ android:textAppearance="@style/TextAppearance.Material.Notification"
+ android:layout_width="match_parent"
+ android:layout_height="0dp"
+ android:singleLine="true"
+ android:ellipsize="end"
+ android:visibility="gone"
+ android:layout_weight="1"
+ />
+ <TextView android:id="@+id/inbox_text4"
+ android:textAppearance="@style/TextAppearance.Material.Notification"
+ android:layout_width="match_parent"
+ android:layout_height="0dp"
+ android:singleLine="true"
+ android:ellipsize="end"
+ android:visibility="gone"
+ android:layout_weight="1"
+ />
+ <TextView android:id="@+id/inbox_text5"
+ android:textAppearance="@style/TextAppearance.Material.Notification"
+ android:layout_width="match_parent"
+ android:layout_height="0dp"
+ android:singleLine="true"
+ android:ellipsize="end"
+ android:visibility="gone"
+ android:layout_weight="1"
+ />
+ <TextView android:id="@+id/inbox_text6"
+ android:textAppearance="@style/TextAppearance.Material.Notification"
+ android:layout_width="match_parent"
+ android:layout_height="0dp"
+ android:singleLine="true"
+ android:ellipsize="end"
+ android:visibility="gone"
+ android:layout_weight="1"
+ />
+ </LinearLayout>
+ <ViewStub android:layout="@layout/notification_material_reply_text"
+ android:id="@+id/notification_material_reply_container"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content" />
<include layout="@layout/notification_material_action_list" />
</LinearLayout>
<include layout="@layout/notification_template_right_icon" />
diff --git a/core/res/res/layout/resolver_list.xml b/core/res/res/layout/resolver_list.xml
index 00c25e6..4b8640c 100644
--- a/core/res/res/layout/resolver_list.xml
+++ b/core/res/res/layout/resolver_list.xml
@@ -25,56 +25,39 @@
android:maxCollapsedHeightSmall="56dp"
android:id="@id/contentPanel">
- <LinearLayout
+ <RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alwaysShow="true"
android:elevation="8dp"
android:background="@color/white" >
+ <TextView android:id="@+id/profile_button"
+ android:layout_width="wrap_content"
+ android:layout_height="48dp"
+ android:layout_marginEnd="8dp"
+ android:paddingStart="8dp"
+ android:paddingEnd="8dp"
+ android:visibility="gone"
+ style="?attr/borderlessButtonStyle"
+ android:textAppearance="?attr/textAppearanceButton"
+ android:textColor="@color/material_deep_teal_500"
+ android:gravity="center_vertical"
+ android:layout_alignParentTop="true"
+ android:layout_alignParentRight="true"
+ android:singleLine="true"/>
<TextView android:id="@+id/title"
- android:layout_width="0dp"
+ android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_weight="1"
android:minHeight="56dp"
android:textAppearance="?attr/textAppearanceMedium"
android:gravity="start|center_vertical"
android:paddingStart="?attr/dialogPreferredPadding"
android:paddingEnd="?attr/dialogPreferredPadding"
android:paddingTop="8dp"
+ android:layout_below="@id/profile_button"
+ android:layout_alignParentLeft="true"
android:paddingBottom="8dp" />
- <LinearLayout android:id="@+id/profile_button"
- android:layout_width="wrap_content"
- android:layout_height="48dp"
- android:layout_marginTop="4dp"
- android:layout_marginEnd="4dp"
- android:paddingStart="8dp"
- android:paddingEnd="8dp"
- android:paddingTop="4dp"
- android:paddingBottom="4dp"
- android:focusable="true"
- android:visibility="gone"
- style="?attr/borderlessButtonStyle">
- <ImageView android:id="@+id/icon"
- android:layout_width="24dp"
- android:layout_height="24dp"
- android:layout_gravity="start|center_vertical"
- android:layout_marginStart="4dp"
- android:layout_marginEnd="16dp"
- android:layout_marginTop="12dp"
- android:layout_marginBottom="12dp"
- android:scaleType="fitCenter" />
- <TextView android:id="@id/text1"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="start|center_vertical"
- android:layout_marginEnd="16dp"
- android:textAppearance="?attr/textAppearanceButton"
- android:textColor="?attr/textColorPrimary"
- android:minLines="1"
- android:maxLines="1"
- android:ellipsize="marquee" />
- </LinearLayout>
- </LinearLayout>
+ </RelativeLayout>
<ListView
android:layout_width="match_parent"
diff --git a/core/res/res/layout/select_dialog_material.xml b/core/res/res/layout/select_dialog_material.xml
index 19ad407..9a068f9a 100644
--- a/core/res/res/layout/select_dialog_material.xml
+++ b/core/res/res/layout/select_dialog_material.xml
@@ -30,6 +30,6 @@
android:scrollbars="vertical"
android:overScrollMode="ifContentScrolls"
android:textAlignment="viewStart"
- android:paddingTop="@dimen/dialog_list_padding_vertical_material"
- android:paddingBottom="@dimen/dialog_list_padding_vertical_material"
- android:clipToPadding="false" />
+ android:clipToPadding="false"
+ android:paddingBottomNoButtons="@dimen/dialog_list_padding_bottom_no_buttons"
+ android:paddingTopNoTitle="@dimen/dialog_list_padding_top_no_title" />
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index 1f958b4..2a16a1e 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -233,8 +233,8 @@
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Inhoud word versteek volgens beleid"</string>
<string name="safeMode" msgid="2788228061547930246">"Veiligmodus"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android-stelsel"</string>
- <string name="user_owner_label" msgid="2804351898001038951">"Persoonlik"</string>
- <string name="managed_profile_label" msgid="6260850669674791528">"Werk"</string>
+ <string name="user_owner_label" msgid="1119010402169916617">"Skakel oor na persoonlik"</string>
+ <string name="managed_profile_label" msgid="5289992269827577857">"Skakel oor na werk"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"Kontakte"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"in te gaan by jou kontakte"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"Ligging"</string>
@@ -1045,7 +1045,8 @@
<string name="no_permissions" msgid="7283357728219338112">"Geen toestemmings benodig nie"</string>
<string name="perm_costs_money" msgid="4902470324142151116">"dit kan jou dalk geld kos"</string>
<string name="dlg_ok" msgid="7376953167039865701">"OK"</string>
- <string name="usb_charging_notification_title" msgid="4004114449249406402">"USB vir batterylaai"</string>
+ <string name="usb_charging_notification_title" msgid="6895185153353640787">"USB laai tans hierdie toestel"</string>
+ <string name="usb_supplying_notification_title" msgid="5310642257296510271">"USB verskaf tans krag aan gekoppelde toestel"</string>
<string name="usb_mtp_notification_title" msgid="8396264943589760855">"USB vir lêeroordrag"</string>
<string name="usb_ptp_notification_title" msgid="1347328437083192112">"USB vir foto-oordrag"</string>
<string name="usb_midi_notification_title" msgid="4850904915889144654">"USB vir MIDI"</string>
@@ -1060,11 +1061,10 @@
<string name="share_remote_bugreport_action" msgid="6249476773913384948">"DEEL"</string>
<string name="decline_remote_bugreport_action" msgid="6230987241608770062">"WEIER"</string>
<string name="select_input_method" msgid="8547250819326693584">"Verander sleutelbord"</string>
- <string name="configure_input_methods" msgid="5673193194563164021">"Ander sleutelborde"</string>
<string name="show_ime" msgid="2506087537466597099">"Hou dit op die skerm terwyl fisieke sleutelbord aktief is"</string>
<string name="hardware" msgid="194658061510127999">"Wys virtuele sleutelbord"</string>
- <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Kies sleutelborduitleg"</string>
- <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Raak om \'n sleutelborduitleg te kies."</string>
+ <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Stel fisieke sleutelbord op"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Tik om taal en uitleg te kies"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"kandidate"</u></string>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index 2623053..0668c35 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -233,8 +233,8 @@
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"ይዘቶች በመመሪያ ተደብቀዋል"</string>
<string name="safeMode" msgid="2788228061547930246">"የሚያስተማምን ሁነታ"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android ስርዓት"</string>
- <string name="user_owner_label" msgid="2804351898001038951">"የግል"</string>
- <string name="managed_profile_label" msgid="6260850669674791528">"ስራ"</string>
+ <string name="user_owner_label" msgid="1119010402169916617">"ወደ የግል ቀይር"</string>
+ <string name="managed_profile_label" msgid="5289992269827577857">"ወደ ሥራ ቀይር"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"ዕውቂያዎች"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"የእርስዎ እውቂያዎች ላይ ይድረሱባቸው"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"መገኛ አካባቢ"</string>
@@ -1045,7 +1045,8 @@
<string name="no_permissions" msgid="7283357728219338112">"ምንም ፍቃዶች አይጠየቁም"</string>
<string name="perm_costs_money" msgid="4902470324142151116">"ይህ ገንዘብ ሊያስወጣዎት ይችላል"</string>
<string name="dlg_ok" msgid="7376953167039865701">"እሺ"</string>
- <string name="usb_charging_notification_title" msgid="4004114449249406402">"ዩኤስቢ ለኃይል መሙላት"</string>
+ <string name="usb_charging_notification_title" msgid="6895185153353640787">"ዩኤስቢ የዚህን መሣሪያ ኃይል በመሙላት ላይ"</string>
+ <string name="usb_supplying_notification_title" msgid="5310642257296510271">"ዩኤስቢ ለተያያዘው መሣሪያ ኃይል በማቅረብ ላይ"</string>
<string name="usb_mtp_notification_title" msgid="8396264943589760855">"ዩኤስቢ ለፋይል ሽግግር"</string>
<string name="usb_ptp_notification_title" msgid="1347328437083192112">"ዩኤስቢ ለፎቶ ሽግግር"</string>
<string name="usb_midi_notification_title" msgid="4850904915889144654">"ዩኤስቢ ለMIDI"</string>
@@ -1060,11 +1061,10 @@
<string name="share_remote_bugreport_action" msgid="6249476773913384948">"አጋራ"</string>
<string name="decline_remote_bugreport_action" msgid="6230987241608770062">"አትቀበል"</string>
<string name="select_input_method" msgid="8547250819326693584">"ቁልፍ ሰሌዳ ይቀይሩ"</string>
- <string name="configure_input_methods" msgid="5673193194563164021">"ሌሎች ቁልፍ ሰሌዳዎች"</string>
<string name="show_ime" msgid="2506087537466597099">"አካላዊ የቁልፍ ሰሌዳ ገቢር ሆኖ ሳለ በማያ ገጽ ላይ አቆየው"</string>
<string name="hardware" msgid="194658061510127999">"ምናባዊ የቁልፍ ሰሌዳን አሳይ"</string>
- <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"የቁልፍ ሰሌዳ አቀማመጥ ምረጥ"</string>
- <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"የቁልፍ ሰሌዳ አቀማመጥ ለመምረጥ ንካ።"</string>
+ <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"አካላዊ ቁልፍ ሰሌዳን ያዋቅሩ"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"ቋንቋ እና አቀማመጥን ለመምረጥ መታ ያድርጉ"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"ዕጩዎች"</u></string>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index b828197..6a7c76c 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -241,8 +241,8 @@
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"تم إخفاء المحتويات بواسطة السياسة"</string>
<string name="safeMode" msgid="2788228061547930246">"الوضع الآمن"</string>
<string name="android_system_label" msgid="6577375335728551336">"نظام Android"</string>
- <string name="user_owner_label" msgid="2804351898001038951">"شخصي"</string>
- <string name="managed_profile_label" msgid="6260850669674791528">"عمل"</string>
+ <string name="user_owner_label" msgid="1119010402169916617">"التبديل إلى الشخصي"</string>
+ <string name="managed_profile_label" msgid="5289992269827577857">"التبديل إلى العمل"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"جهات الاتصال"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"الوصول إلى جهات اتصالك"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"الموقع"</string>
@@ -1077,7 +1077,8 @@
<string name="no_permissions" msgid="7283357728219338112">"لا أذونات مطلوبة"</string>
<string name="perm_costs_money" msgid="4902470324142151116">"قد يكلفك هذا مالاً."</string>
<string name="dlg_ok" msgid="7376953167039865701">"موافق"</string>
- <string name="usb_charging_notification_title" msgid="4004114449249406402">"USB للشحن"</string>
+ <string name="usb_charging_notification_title" msgid="6895185153353640787">"يتم استخدام الاتصال عبر USB لشحن هذا الجهاز"</string>
+ <string name="usb_supplying_notification_title" msgid="5310642257296510271">"يتم استخدام الاتصال عبر USB لإمداد الجهاز المتصل بالطاقة"</string>
<string name="usb_mtp_notification_title" msgid="8396264943589760855">"USB لنقل الملفات"</string>
<string name="usb_ptp_notification_title" msgid="1347328437083192112">"USB لنقل الصور"</string>
<string name="usb_midi_notification_title" msgid="4850904915889144654">"USB لـ MIDI"</string>
@@ -1092,11 +1093,10 @@
<string name="share_remote_bugreport_action" msgid="6249476773913384948">"مشاركة"</string>
<string name="decline_remote_bugreport_action" msgid="6230987241608770062">"رفض"</string>
<string name="select_input_method" msgid="8547250819326693584">"تغيير لوحة المفاتيح"</string>
- <string name="configure_input_methods" msgid="5673193194563164021">"لوحات المفاتيح الأخرى"</string>
<string name="show_ime" msgid="2506087537466597099">"استمرار عرضها على الشاشة أثناء نشاط لوحة المفاتيح الفعلية"</string>
<string name="hardware" msgid="194658061510127999">"إظهار لوحة المفاتيح الظاهرية"</string>
- <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"تحديد تخطيط لوحة مفاتيح"</string>
- <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"المس لتحديد تخطيط لوحة مفاتيح."</string>
+ <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"تهيئة لوحة المفاتيح الفعلية"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"انقر لاختيار لغة وتنسيق"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" أ ب ت ث ج ح خ د ذ ر ز س ش ص ض ط ظ ع غ ف ق ك ل م ن ه و ي"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789 أ ب ت ث ج ح خ د ذ ر ز س ش ص ض ط ظ ع غ ف ق ك ل م ن ه و ي"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"العناصر المرشحة"</u></string>
diff --git a/core/res/res/values-az-rAZ/strings.xml b/core/res/res/values-az-rAZ/strings.xml
index 25a979b..e76ce87 100644
--- a/core/res/res/values-az-rAZ/strings.xml
+++ b/core/res/res/values-az-rAZ/strings.xml
@@ -233,8 +233,8 @@
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Məzmun siyasət tərəfindən gizlədilib"</string>
<string name="safeMode" msgid="2788228061547930246">"Təhlükəsiz rejim"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android sistemi"</string>
- <string name="user_owner_label" msgid="2804351898001038951">"Şəxsi"</string>
- <string name="managed_profile_label" msgid="6260850669674791528">"İş"</string>
+ <string name="user_owner_label" msgid="1119010402169916617">"Şəxsi profilə keçirin"</string>
+ <string name="managed_profile_label" msgid="5289992269827577857">"İş profilinə keçirin"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"Kontaktlar"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"kontaktlarınıza daxil olun"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"Yer"</string>
@@ -1045,7 +1045,8 @@
<string name="no_permissions" msgid="7283357728219338112">"Heç bir icazə tələb olunmur"</string>
<string name="perm_costs_money" msgid="4902470324142151116">"bununla sizdən xərc tutula bilər"</string>
<string name="dlg_ok" msgid="7376953167039865701">"OK"</string>
- <string name="usb_charging_notification_title" msgid="4004114449249406402">"Enerji doldurmaq üçün USB"</string>
+ <string name="usb_charging_notification_title" msgid="6895185153353640787">"USB bu cihaza enerji doldurur"</string>
+ <string name="usb_supplying_notification_title" msgid="5310642257296510271">"Qolulmuş cihaz üçün USB enerji tədarükü"</string>
<string name="usb_mtp_notification_title" msgid="8396264943589760855">"Fayl transferi üçün USB"</string>
<string name="usb_ptp_notification_title" msgid="1347328437083192112">"Foto transfer üçün USB"</string>
<string name="usb_midi_notification_title" msgid="4850904915889144654">"MIDI üçün USB"</string>
@@ -1060,11 +1061,10 @@
<string name="share_remote_bugreport_action" msgid="6249476773913384948">"PAYLAŞIN"</string>
<string name="decline_remote_bugreport_action" msgid="6230987241608770062">"RƏDD EDİN"</string>
<string name="select_input_method" msgid="8547250819326693584">"Klaviaturanı dəyişin"</string>
- <string name="configure_input_methods" msgid="5673193194563164021">"Digər klaviaturalar"</string>
<string name="show_ime" msgid="2506087537466597099">"Fiziki klaviatura aktiv olduğu halda ekranda saxlayın"</string>
<string name="hardware" msgid="194658061510127999">"Virtual klaviaturanı göstərin"</string>
- <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Klaviatura sxemi seçin"</string>
- <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Klaviatura tərtibatı seçmək üçün toxunun."</string>
+ <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Fiziki klaviaturanı konfiqurasiya edin"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Dil və tərtibatı seçmək üçün tıklayın"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCÇDEƏFGĞHXIİJKQLMNOÖPRSŞTUÜVYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCÇDEƏFGĞHİIJKLMNOÖPQRSŞTUÜVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"namizədlər"</u></string>
diff --git a/core/res/res/values-b+sr+Latn/strings.xml b/core/res/res/values-b+sr+Latn/strings.xml
index 3eff6f3..9231e9a 100644
--- a/core/res/res/values-b+sr+Latn/strings.xml
+++ b/core/res/res/values-b+sr+Latn/strings.xml
@@ -235,8 +235,8 @@
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Sadržaj je sakriven smernicama"</string>
<string name="safeMode" msgid="2788228061547930246">"Bezbedni režim"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android sistem"</string>
- <string name="user_owner_label" msgid="2804351898001038951">"Lično"</string>
- <string name="managed_profile_label" msgid="6260850669674791528">"Posao"</string>
+ <string name="user_owner_label" msgid="1119010402169916617">"Pređi na Lični profil"</string>
+ <string name="managed_profile_label" msgid="5289992269827577857">"Pređi na profil za Work"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"Kontakti"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"pristupi kontaktima"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"Lokacija"</string>
@@ -1053,7 +1053,8 @@
<string name="no_permissions" msgid="7283357728219338112">"Nije potrebna nijedna dozvola"</string>
<string name="perm_costs_money" msgid="4902470324142151116">"ovo će vam možda biti naplaćeno"</string>
<string name="dlg_ok" msgid="7376953167039865701">"Potvrdi"</string>
- <string name="usb_charging_notification_title" msgid="4004114449249406402">"USB za punjenje"</string>
+ <string name="usb_charging_notification_title" msgid="6895185153353640787">"USB puni ovaj uređaj"</string>
+ <string name="usb_supplying_notification_title" msgid="5310642257296510271">"USB snabdeva energijom priključeni uređaj"</string>
<string name="usb_mtp_notification_title" msgid="8396264943589760855">"USB za prenos datoteka"</string>
<string name="usb_ptp_notification_title" msgid="1347328437083192112">"USB za prenos slika"</string>
<string name="usb_midi_notification_title" msgid="4850904915889144654">"USB za MIDI"</string>
@@ -1068,11 +1069,10 @@
<string name="share_remote_bugreport_action" msgid="6249476773913384948">"DELI"</string>
<string name="decline_remote_bugreport_action" msgid="6230987241608770062">"ODBIJ"</string>
<string name="select_input_method" msgid="8547250819326693584">"Promenite tastaturu"</string>
- <string name="configure_input_methods" msgid="5673193194563164021">"Druge tastature"</string>
<string name="show_ime" msgid="2506087537466597099">"Zadrži ga na ekranu dok je fizička tastatura aktivna"</string>
<string name="hardware" msgid="194658061510127999">"Prikaži virtuelnu tastaturu"</string>
- <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Izbor rasporeda tastature"</string>
- <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Dodirnite da biste izabrali raspored tastature."</string>
+ <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Konfigurišite fizičku tastaturu"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Dodirnite da biste izabrali jezik i raspored"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"kandidati"</u></string>
diff --git a/core/res/res/values-be-rBY/strings.xml b/core/res/res/values-be-rBY/strings.xml
index 7b85628..73a8e04 100644
--- a/core/res/res/values-be-rBY/strings.xml
+++ b/core/res/res/values-be-rBY/strings.xml
@@ -237,8 +237,8 @@
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Змесціва, схаванае ў адпаведнасці з палітыкай"</string>
<string name="safeMode" msgid="2788228061547930246">"Бяспечны рэжым"</string>
<string name="android_system_label" msgid="6577375335728551336">"Сістэма Android"</string>
- <string name="user_owner_label" msgid="2804351898001038951">"Асабістыя"</string>
- <string name="managed_profile_label" msgid="6260850669674791528">"Працоўны"</string>
+ <string name="user_owner_label" msgid="1119010402169916617">"Пераключыцца на асабісты"</string>
+ <string name="managed_profile_label" msgid="5289992269827577857">"Пераключыцца на рабочы"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"Кантакты"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"атрымліваць доступ да вашых кантактаў"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"Месцазнаходжанне"</string>
@@ -1061,7 +1061,8 @@
<string name="no_permissions" msgid="7283357728219338112">"Дазволу не патрабуецца"</string>
<string name="perm_costs_money" msgid="4902470324142151116">"за гэта можа спаганяцца плата"</string>
<string name="dlg_ok" msgid="7376953167039865701">"ОК"</string>
- <string name="usb_charging_notification_title" msgid="4004114449249406402">"USB для зарадкі"</string>
+ <string name="usb_charging_notification_title" msgid="6895185153353640787">"Па USB зараджаецца гэта прыладу"</string>
+ <string name="usb_supplying_notification_title" msgid="5310642257296510271">"Па USB падачецца сілкаванне падключанай прыладзе"</string>
<string name="usb_mtp_notification_title" msgid="8396264943589760855">"USB для перадачы файлаў"</string>
<string name="usb_ptp_notification_title" msgid="1347328437083192112">"USB для перадачы фота"</string>
<string name="usb_midi_notification_title" msgid="4850904915889144654">"USB для MIDI"</string>
@@ -1076,11 +1077,10 @@
<string name="share_remote_bugreport_action" msgid="6249476773913384948">"АБАГУЛІЦЬ"</string>
<string name="decline_remote_bugreport_action" msgid="6230987241608770062">"АДХІЛІЦЬ"</string>
<string name="select_input_method" msgid="8547250819326693584">"Змяніць клавіятуру"</string>
- <string name="configure_input_methods" msgid="5673193194563164021">"Іншыя праграмныя клавіятуры"</string>
<string name="show_ime" msgid="2506087537466597099">"Захоўваць яе на экране ў той час, калі фізічная клавіятура актыўная"</string>
<string name="hardware" msgid="194658061510127999">"Паказаць віртуальную клавіятуру"</string>
- <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Выбраць раскладку клавіятуры"</string>
- <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Націсніце, каб выбраць раскладку клавіятуры."</string>
+ <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Наладжванне фізічнай клавіятуры"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Дакраніцеся, каб выбраць мову і раскладку"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" АБВГДЕЁЖЗІЙКЛМНОПРСТУЎФХЦЧШ\'ЫЬЭЮЯ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"кандыдат."</u></string>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index 4515e80..76c7002 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -233,8 +233,8 @@
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Съдържанието е скрито чрез правило"</string>
<string name="safeMode" msgid="2788228061547930246">"Безопасен режим"</string>
<string name="android_system_label" msgid="6577375335728551336">"Системно от Android"</string>
- <string name="user_owner_label" msgid="2804351898001038951">"Личен"</string>
- <string name="managed_profile_label" msgid="6260850669674791528">"Служебен"</string>
+ <string name="user_owner_label" msgid="1119010402169916617">"Превключване към личния потребителски профил"</string>
+ <string name="managed_profile_label" msgid="5289992269827577857">"Превключване към служебния пoтребителски профил"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"Контакти"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"има достъп до контактите ви"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"Местоположение"</string>
@@ -1045,7 +1045,8 @@
<string name="no_permissions" msgid="7283357728219338112">"Не се изискват разрешения"</string>
<string name="perm_costs_money" msgid="4902470324142151116">"това може да ви струва пари"</string>
<string name="dlg_ok" msgid="7376953167039865701">"OK"</string>
- <string name="usb_charging_notification_title" msgid="4004114449249406402">"USB за зареждане"</string>
+ <string name="usb_charging_notification_title" msgid="6895185153353640787">"През USB се зарежда това устройство"</string>
+ <string name="usb_supplying_notification_title" msgid="5310642257296510271">"През USB се зарежда свързаното устройство"</string>
<string name="usb_mtp_notification_title" msgid="8396264943589760855">"USB за прехвърляне на файлове"</string>
<string name="usb_ptp_notification_title" msgid="1347328437083192112">"USB за прехвърляне на снимки"</string>
<string name="usb_midi_notification_title" msgid="4850904915889144654">"USB за MIDI"</string>
@@ -1060,11 +1061,10 @@
<string name="share_remote_bugreport_action" msgid="6249476773913384948">"СПОДЕЛЯНЕ"</string>
<string name="decline_remote_bugreport_action" msgid="6230987241608770062">"ОТХВЪРЛЯНЕ"</string>
<string name="select_input_method" msgid="8547250819326693584">"Промяна на клавиатурата"</string>
- <string name="configure_input_methods" msgid="5673193194563164021">"Други клавиатури"</string>
<string name="show_ime" msgid="2506087537466597099">"Показване на екрана, докато физическата клавиатура е активна"</string>
<string name="hardware" msgid="194658061510127999">"Показване на вирт. клавиатура"</string>
- <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Избиране на клавиатурна подредба"</string>
- <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Докоснете, за да изберете клавиатурна подредба."</string>
+ <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Конфигуриране на физическата клавиатура"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Докоснете, за да изберете език и подредба"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"кандидати"</u></string>
diff --git a/core/res/res/values-bn-rBD/strings.xml b/core/res/res/values-bn-rBD/strings.xml
index 03faf2f..620e532 100644
--- a/core/res/res/values-bn-rBD/strings.xml
+++ b/core/res/res/values-bn-rBD/strings.xml
@@ -233,8 +233,8 @@
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"নীতির কারণে সামগ্রী লুকানো আছে"</string>
<string name="safeMode" msgid="2788228061547930246">"নিরাপদ মোড"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android সিস্টেম"</string>
- <string name="user_owner_label" msgid="2804351898001038951">"ব্যক্তিগত"</string>
- <string name="managed_profile_label" msgid="6260850669674791528">"কর্মক্ষেত্র"</string>
+ <string name="user_owner_label" msgid="1119010402169916617">"ব্যক্তিগততে পাল্টান"</string>
+ <string name="managed_profile_label" msgid="5289992269827577857">"কর্মস্থানে পাল্টান"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"পরিচিতি"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"আপনার পরিচিতিগুলিতে অ্যাক্সেস করুন"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"অবস্থান"</string>
@@ -1045,7 +1045,8 @@
<string name="no_permissions" msgid="7283357728219338112">"কোনো অনুমতির প্রয়োজন নেই"</string>
<string name="perm_costs_money" msgid="4902470324142151116">"এর জন্য অর্থপ্রদান করতে হতে পারে"</string>
<string name="dlg_ok" msgid="7376953167039865701">"ঠিক আছে"</string>
- <string name="usb_charging_notification_title" msgid="4004114449249406402">"চার্জ করার জন্য USB"</string>
+ <string name="usb_charging_notification_title" msgid="6895185153353640787">"এই ডিভাইসটি USB দ্বারা চার্জ করা হচ্ছে"</string>
+ <string name="usb_supplying_notification_title" msgid="5310642257296510271">"সংযুক্ত ডিভাইসটিতে USB পাওয়ার সরবরাহ করছে"</string>
<string name="usb_mtp_notification_title" msgid="8396264943589760855">"ফাইল স্থানান্তরের জন্য USB"</string>
<string name="usb_ptp_notification_title" msgid="1347328437083192112">"ফটো স্থানান্তরের জন্য USB"</string>
<string name="usb_midi_notification_title" msgid="4850904915889144654">"MIDI এর জন্য USB"</string>
@@ -1060,11 +1061,10 @@
<string name="share_remote_bugreport_action" msgid="6249476773913384948">"শেয়ার করুন"</string>
<string name="decline_remote_bugreport_action" msgid="6230987241608770062">"অস্বীকার করুন"</string>
<string name="select_input_method" msgid="8547250819326693584">"কীবোর্ড পরিবর্তন করুন"</string>
- <string name="configure_input_methods" msgid="5673193194563164021">"অন্যান্য কীবোর্ড"</string>
<string name="show_ime" msgid="2506087537466597099">"ফিজিক্যাল কীবোর্ড সক্রিয় থাকার সময় এটিকে স্ক্রীনে রাখুন"</string>
<string name="hardware" msgid="194658061510127999">"ভার্চুয়াল কীবোর্ড দেখান"</string>
- <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"কীবোর্ডের লেআউট নির্বাচন করুন"</string>
- <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"একটি কীবোর্ডের লেআউট নির্বাচন করতে স্পর্শ করুন৷"</string>
+ <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"ফিজিক্যাল কীবোর্ড কনফিগার করুন"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"ভাষা এবং লেআউট নির্বাচন করুন আলতো চাপ দিন"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"প্রার্থীরা"</u></string>
diff --git a/core/res/res/values-bs-rBA/strings.xml b/core/res/res/values-bs-rBA/strings.xml
index 7e9f44f..82639af 100644
--- a/core/res/res/values-bs-rBA/strings.xml
+++ b/core/res/res/values-bs-rBA/strings.xml
@@ -235,8 +235,8 @@
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Sadržaj skriven u skladu sa pravilima"</string>
<string name="safeMode" msgid="2788228061547930246">"Siguran način rada"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android sistem"</string>
- <string name="user_owner_label" msgid="2804351898001038951">"Lično"</string>
- <string name="managed_profile_label" msgid="6260850669674791528">"Poslovni"</string>
+ <string name="user_owner_label" msgid="1119010402169916617">"Prebacite se na lični"</string>
+ <string name="managed_profile_label" msgid="5289992269827577857">"Prebacite se na radni"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"Kontakti"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"pristupa vašim kontaktima"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"Lokacija"</string>
@@ -1053,7 +1053,8 @@
<string name="no_permissions" msgid="7283357728219338112">"Nisu potrebne dozvole"</string>
<string name="perm_costs_money" msgid="4902470324142151116">"ovo se možda dodatno plaća"</string>
<string name="dlg_ok" msgid="7376953167039865701">"Uredu"</string>
- <string name="usb_charging_notification_title" msgid="4004114449249406402">"USB za punjenje"</string>
+ <string name="usb_charging_notification_title" msgid="6895185153353640787">"Ovaj uređaj se puni preko USB-a"</string>
+ <string name="usb_supplying_notification_title" msgid="5310642257296510271">"USB napaja priključeni uređaj"</string>
<string name="usb_mtp_notification_title" msgid="8396264943589760855">"USB za prijenos fajlova"</string>
<string name="usb_ptp_notification_title" msgid="1347328437083192112">"USB za prijenos slika"</string>
<string name="usb_midi_notification_title" msgid="4850904915889144654">"USB za MIDI"</string>
@@ -1068,11 +1069,10 @@
<string name="share_remote_bugreport_action" msgid="6249476773913384948">"PODIJELI"</string>
<string name="decline_remote_bugreport_action" msgid="6230987241608770062">"ODBACI"</string>
<string name="select_input_method" msgid="8547250819326693584">"Promijeni tastaturu"</string>
- <string name="configure_input_methods" msgid="5673193194563164021">"Ostale tastature"</string>
<string name="show_ime" msgid="2506087537466597099">"Prikaži na ekranu dok je fizička tastatura aktivna"</string>
<string name="hardware" msgid="194658061510127999">"Prikaži virtualnu tastaturu"</string>
- <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Odaberite raspored tastature"</string>
- <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Dodirnite za odabir rasporeda tastature."</string>
+ <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Konfiguriraj fizičku tastaturu"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Dodirnite za odabir jezika i rasporeda"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"kandidati"</u></string>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index e59c936..6fcadfa 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -233,8 +233,8 @@
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Contingut amagat de conformitat amb la política"</string>
<string name="safeMode" msgid="2788228061547930246">"Mode segur"</string>
<string name="android_system_label" msgid="6577375335728551336">"Sistema Android"</string>
- <string name="user_owner_label" msgid="2804351898001038951">"Personal"</string>
- <string name="managed_profile_label" msgid="6260850669674791528">"Feina"</string>
+ <string name="user_owner_label" msgid="1119010402169916617">"Canvia al perfil personal"</string>
+ <string name="managed_profile_label" msgid="5289992269827577857">"Canvia al perfil professional"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"Contactes"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"accedir als contactes"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"Ubicació"</string>
@@ -1045,7 +1045,8 @@
<string name="no_permissions" msgid="7283357728219338112">"No cal cap permís"</string>
<string name="perm_costs_money" msgid="4902470324142151116">"pot ser que comporti càrrecs"</string>
<string name="dlg_ok" msgid="7376953167039865701">"D\'acord"</string>
- <string name="usb_charging_notification_title" msgid="4004114449249406402">"USB per carregar"</string>
+ <string name="usb_charging_notification_title" msgid="6895185153353640787">"L\'USB està carregant el dispositiu"</string>
+ <string name="usb_supplying_notification_title" msgid="5310642257296510271">"L\'USB subministra energia al dispositiu connectat"</string>
<string name="usb_mtp_notification_title" msgid="8396264943589760855">"USB per transferir fitxers"</string>
<string name="usb_ptp_notification_title" msgid="1347328437083192112">"USB per transferir fotos"</string>
<string name="usb_midi_notification_title" msgid="4850904915889144654">"USB per a MIDI"</string>
@@ -1060,11 +1061,10 @@
<string name="share_remote_bugreport_action" msgid="6249476773913384948">"COMPARTEIX"</string>
<string name="decline_remote_bugreport_action" msgid="6230987241608770062">"REBUTJA"</string>
<string name="select_input_method" msgid="8547250819326693584">"Canvia el teclat"</string>
- <string name="configure_input_methods" msgid="5673193194563164021">"Altres teclats"</string>
<string name="show_ime" msgid="2506087537466597099">"El deixa a la pantalla mentre el teclat físic està actiu"</string>
<string name="hardware" msgid="194658061510127999">"Mostra el teclat virtual"</string>
- <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Selecciona una disposició de teclat"</string>
- <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Toca per seleccionar una disposició de teclat."</string>
+ <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Configura el teclat físic"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Toca per seleccionar l\'idioma i el disseny"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"candidats"</u></string>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index 237d44d..127d38b 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -237,8 +237,8 @@
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Obsah skrytý zásadami"</string>
<string name="safeMode" msgid="2788228061547930246">"Nouzový režim"</string>
<string name="android_system_label" msgid="6577375335728551336">"Systém Android"</string>
- <string name="user_owner_label" msgid="2804351898001038951">"Osobní"</string>
- <string name="managed_profile_label" msgid="6260850669674791528">"Práce"</string>
+ <string name="user_owner_label" msgid="1119010402169916617">"Přepnout na osobní profil"</string>
+ <string name="managed_profile_label" msgid="5289992269827577857">"Přepnout na pracovní profil"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"Kontakty"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"přístup ke kontaktům"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"Poloha"</string>
@@ -1061,7 +1061,8 @@
<string name="no_permissions" msgid="7283357728219338112">"Nejsou vyžadována žádná oprávnění"</string>
<string name="perm_costs_money" msgid="4902470324142151116">"může vás to něco stát"</string>
<string name="dlg_ok" msgid="7376953167039865701">"OK"</string>
- <string name="usb_charging_notification_title" msgid="4004114449249406402">"USB na nabíjení"</string>
+ <string name="usb_charging_notification_title" msgid="6895185153353640787">"Nabíjení zařízení přes USB"</string>
+ <string name="usb_supplying_notification_title" msgid="5310642257296510271">"Připojené zařízení se nabíjí přes USB"</string>
<string name="usb_mtp_notification_title" msgid="8396264943589760855">"USB na přenos souborů"</string>
<string name="usb_ptp_notification_title" msgid="1347328437083192112">"USB na přenos fotek"</string>
<string name="usb_midi_notification_title" msgid="4850904915889144654">"USB v režimu MIDI"</string>
@@ -1076,11 +1077,10 @@
<string name="share_remote_bugreport_action" msgid="6249476773913384948">"SDÍLET"</string>
<string name="decline_remote_bugreport_action" msgid="6230987241608770062">"ODMÍTNOUT"</string>
<string name="select_input_method" msgid="8547250819326693584">"Změna klávesnice"</string>
- <string name="configure_input_methods" msgid="5673193194563164021">"Další klávesnice"</string>
<string name="show_ime" msgid="2506087537466597099">"Ponechat na obrazovce, když je aktivní fyzická klávesnice"</string>
<string name="hardware" msgid="194658061510127999">"Zobrazit virtuální klávesnici"</string>
- <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Výběr rozložení klávesnice"</string>
- <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Dotykem vyberte rozložení klávesnice."</string>
+ <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Konfigurace fyzické klávesnice"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Klepnutím vyberte jazyk a rozvržení"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" AÁBCČDĎEÉĚFGHCHIÍJKLMNŇOÓPQRŘSŠTŤUÚVWXYÝZŽ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789AÁBCČDĎEÉĚFGHCHIÍJKLMNŇOÓPQRŘSŠTŤUÚVWXYÝZŽ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"kandidáti"</u></string>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index 391b012..407f1f8 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -233,8 +233,8 @@
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Indholdet er skjult af politikken"</string>
<string name="safeMode" msgid="2788228061547930246">"Sikker tilstand"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android-system"</string>
- <string name="user_owner_label" msgid="2804351898001038951">"Personlig"</string>
- <string name="managed_profile_label" msgid="6260850669674791528">"Arbejde"</string>
+ <string name="user_owner_label" msgid="1119010402169916617">"Skift til Tilpasset"</string>
+ <string name="managed_profile_label" msgid="5289992269827577857">"Skift til arbejde"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"Kontaktpersoner"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"have adgang til dine kontaktpersoner"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"Placering"</string>
@@ -1045,7 +1045,8 @@
<string name="no_permissions" msgid="7283357728219338112">"Der kræves ingen tilladelser"</string>
<string name="perm_costs_money" msgid="4902470324142151116">"dette kan koste dig penge"</string>
<string name="dlg_ok" msgid="7376953167039865701">"OK"</string>
- <string name="usb_charging_notification_title" msgid="4004114449249406402">"USB til opladning"</string>
+ <string name="usb_charging_notification_title" msgid="6895185153353640787">"USB, der oplader denne enhed"</string>
+ <string name="usb_supplying_notification_title" msgid="5310642257296510271">"USB, der leverer strøm til den tilsluttede enhed"</string>
<string name="usb_mtp_notification_title" msgid="8396264943589760855">"USB til filoverførsel"</string>
<string name="usb_ptp_notification_title" msgid="1347328437083192112">"USB til billedoverførsel"</string>
<string name="usb_midi_notification_title" msgid="4850904915889144654">"USB til MIDI"</string>
@@ -1060,11 +1061,10 @@
<string name="share_remote_bugreport_action" msgid="6249476773913384948">"DEL"</string>
<string name="decline_remote_bugreport_action" msgid="6230987241608770062">"AFVIS"</string>
<string name="select_input_method" msgid="8547250819326693584">"Skift tastatur"</string>
- <string name="configure_input_methods" msgid="5673193194563164021">"Andre tastaturer"</string>
<string name="show_ime" msgid="2506087537466597099">"Behold den på skærmen, mens det fysiske tastatur er aktivt"</string>
<string name="hardware" msgid="194658061510127999">"Vis virtuelt tastatur"</string>
- <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Vælg tastaturlayout"</string>
- <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Tryk for at vælge et tastaturlayout."</string>
+ <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Konfigurer fysisk tastatur"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Tryk for at vælge sprog og layout"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"kandidater"</u></string>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index d95bdda..e539a28 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -233,8 +233,8 @@
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Inhalte aufgrund der Richtlinien ausgeblendet"</string>
<string name="safeMode" msgid="2788228061547930246">"Abgesicherter Modus"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android-System"</string>
- <string name="user_owner_label" msgid="2804351898001038951">"Privat"</string>
- <string name="managed_profile_label" msgid="6260850669674791528">"Geschäftlich"</string>
+ <string name="user_owner_label" msgid="1119010402169916617">"Zu \"Privat\" wechseln"</string>
+ <string name="managed_profile_label" msgid="5289992269827577857">"Zu \"Arbeit\" wechseln"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"Kontakte"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"auf Kontakte zuzugreifen"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"Standort"</string>
@@ -1045,7 +1045,8 @@
<string name="no_permissions" msgid="7283357728219338112">"Keine Berechtigungen erforderlich"</string>
<string name="perm_costs_money" msgid="4902470324142151116">"Hierfür können Gebühren anfallen."</string>
<string name="dlg_ok" msgid="7376953167039865701">"OK"</string>
- <string name="usb_charging_notification_title" msgid="4004114449249406402">"USB zum Aufladen"</string>
+ <string name="usb_charging_notification_title" msgid="6895185153353640787">"Gerät wird über USB aufgeladen"</string>
+ <string name="usb_supplying_notification_title" msgid="5310642257296510271">"Angeschlossenes Gerät wird über USB aufgeladen"</string>
<string name="usb_mtp_notification_title" msgid="8396264943589760855">"USB für die Dateiübertragung"</string>
<string name="usb_ptp_notification_title" msgid="1347328437083192112">"USB für die Fotoübertragung"</string>
<string name="usb_midi_notification_title" msgid="4850904915889144654">"USB für MIDI"</string>
@@ -1060,11 +1061,10 @@
<string name="share_remote_bugreport_action" msgid="6249476773913384948">"TEILEN"</string>
<string name="decline_remote_bugreport_action" msgid="6230987241608770062">"ABLEHNEN"</string>
<string name="select_input_method" msgid="8547250819326693584">"Tastatur ändern"</string>
- <string name="configure_input_methods" msgid="5673193194563164021">"Weitere Tastaturen"</string>
<string name="show_ime" msgid="2506087537466597099">"Auf dem Display einblenden, wenn die physische Tastatur aktiv ist"</string>
<string name="hardware" msgid="194658061510127999">"Virtuelle Tastatur einblenden"</string>
- <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Tastaturlayout auswählen"</string>
- <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Zum Auswählen eines Tastaturlayouts berühren"</string>
+ <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Physische Tastatur konfigurieren"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Zum Auswählen von Sprache und Layout tippen"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"Kandidaten"</u></string>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index ce0805f..1e891d0 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -233,8 +233,8 @@
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Το περιεχόμενο είναι κρυφό βάσει πολιτικής"</string>
<string name="safeMode" msgid="2788228061547930246">"Ασφαλής λειτουργία"</string>
<string name="android_system_label" msgid="6577375335728551336">"Σύστημα Android"</string>
- <string name="user_owner_label" msgid="2804351898001038951">"Προσωπικό"</string>
- <string name="managed_profile_label" msgid="6260850669674791528">"Εργασία"</string>
+ <string name="user_owner_label" msgid="1119010402169916617">"Μετάβαση σε προσωπικό προφίλ"</string>
+ <string name="managed_profile_label" msgid="5289992269827577857">"Μετάβαση σε προφίλ εργασίας"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"Επαφές"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"πρόσβαση στις επαφές σας"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"Τοποθεσία"</string>
@@ -1045,7 +1045,8 @@
<string name="no_permissions" msgid="7283357728219338112">"Δεν απαιτούνται άδειες"</string>
<string name="perm_costs_money" msgid="4902470324142151116">"ενδέχεται να χρεωθείτε"</string>
<string name="dlg_ok" msgid="7376953167039865701">"ΟΚ"</string>
- <string name="usb_charging_notification_title" msgid="4004114449249406402">"USB για φόρτιση"</string>
+ <string name="usb_charging_notification_title" msgid="6895185153353640787">"Αυτή η συσκευή φορτίζεται μέσω USB"</string>
+ <string name="usb_supplying_notification_title" msgid="5310642257296510271">"Η συνδεδεμένη συσκευή τροφοδοτείται μέσω USB"</string>
<string name="usb_mtp_notification_title" msgid="8396264943589760855">"USB για μεταφορά αρχείων"</string>
<string name="usb_ptp_notification_title" msgid="1347328437083192112">"USB για μεταφορά φωτογραφιών"</string>
<string name="usb_midi_notification_title" msgid="4850904915889144654">"USB για MIDI"</string>
@@ -1060,11 +1061,10 @@
<string name="share_remote_bugreport_action" msgid="6249476773913384948">"ΚΟΙΝΟΠΟΙΗΣΗ"</string>
<string name="decline_remote_bugreport_action" msgid="6230987241608770062">"ΑΠΟΡΡΙΨΗ"</string>
<string name="select_input_method" msgid="8547250819326693584">"Αλλαγή πληκτρολογίου"</string>
- <string name="configure_input_methods" msgid="5673193194563164021">"Άλλα πληκτρολόγια"</string>
<string name="show_ime" msgid="2506087537466597099">"Να παραμένει στην οθόνη όταν είναι ενεργό το φυσικό πληκτρολόγιο"</string>
<string name="hardware" msgid="194658061510127999">"Εμφάνιση εικονικού πληκτρολ."</string>
- <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Επιλογή διάταξης πληκτρολογίου"</string>
- <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Αγγίξτε για να επιλέξετε διάταξη πληκτρολογίου."</string>
+ <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Διαμόρφωση φυσικού πληκτρολογίου"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Πατήστε για να επιλέξετε γλώσσα και διάταξη"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"υποψήφιοι"</u></string>
diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml
index 335f1f0..b94222c 100644
--- a/core/res/res/values-en-rAU/strings.xml
+++ b/core/res/res/values-en-rAU/strings.xml
@@ -233,8 +233,8 @@
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Contents hidden by policy"</string>
<string name="safeMode" msgid="2788228061547930246">"Safe mode"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android system"</string>
- <string name="user_owner_label" msgid="2804351898001038951">"Personal"</string>
- <string name="managed_profile_label" msgid="6260850669674791528">"Work"</string>
+ <string name="user_owner_label" msgid="1119010402169916617">"Switch to Personal"</string>
+ <string name="managed_profile_label" msgid="5289992269827577857">"Switch to Work"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"Contacts"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"access your contacts"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"Location"</string>
@@ -1045,7 +1045,8 @@
<string name="no_permissions" msgid="7283357728219338112">"No permission required"</string>
<string name="perm_costs_money" msgid="4902470324142151116">"this may cost you money"</string>
<string name="dlg_ok" msgid="7376953167039865701">"OK"</string>
- <string name="usb_charging_notification_title" msgid="4004114449249406402">"USB for charging"</string>
+ <string name="usb_charging_notification_title" msgid="6895185153353640787">"USB charging this device"</string>
+ <string name="usb_supplying_notification_title" msgid="5310642257296510271">"USB supplying power to attached device"</string>
<string name="usb_mtp_notification_title" msgid="8396264943589760855">"USB for file transfer"</string>
<string name="usb_ptp_notification_title" msgid="1347328437083192112">"USB for photo transfer"</string>
<string name="usb_midi_notification_title" msgid="4850904915889144654">"USB for MIDI"</string>
@@ -1060,11 +1061,10 @@
<string name="share_remote_bugreport_action" msgid="6249476773913384948">"SHARE"</string>
<string name="decline_remote_bugreport_action" msgid="6230987241608770062">"DECLINE"</string>
<string name="select_input_method" msgid="8547250819326693584">"Change keyboard"</string>
- <string name="configure_input_methods" msgid="5673193194563164021">"Other keyboards"</string>
<string name="show_ime" msgid="2506087537466597099">"Keep it on screen while physical keyboard is active"</string>
<string name="hardware" msgid="194658061510127999">"Show virtual keyboard"</string>
- <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Select keyboard layout"</string>
- <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Touch to select a keyboard layout."</string>
+ <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Configure physical keyboard"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Tap to select language and layout"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"candidates"</u></string>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index 335f1f0..b94222c 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -233,8 +233,8 @@
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Contents hidden by policy"</string>
<string name="safeMode" msgid="2788228061547930246">"Safe mode"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android system"</string>
- <string name="user_owner_label" msgid="2804351898001038951">"Personal"</string>
- <string name="managed_profile_label" msgid="6260850669674791528">"Work"</string>
+ <string name="user_owner_label" msgid="1119010402169916617">"Switch to Personal"</string>
+ <string name="managed_profile_label" msgid="5289992269827577857">"Switch to Work"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"Contacts"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"access your contacts"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"Location"</string>
@@ -1045,7 +1045,8 @@
<string name="no_permissions" msgid="7283357728219338112">"No permission required"</string>
<string name="perm_costs_money" msgid="4902470324142151116">"this may cost you money"</string>
<string name="dlg_ok" msgid="7376953167039865701">"OK"</string>
- <string name="usb_charging_notification_title" msgid="4004114449249406402">"USB for charging"</string>
+ <string name="usb_charging_notification_title" msgid="6895185153353640787">"USB charging this device"</string>
+ <string name="usb_supplying_notification_title" msgid="5310642257296510271">"USB supplying power to attached device"</string>
<string name="usb_mtp_notification_title" msgid="8396264943589760855">"USB for file transfer"</string>
<string name="usb_ptp_notification_title" msgid="1347328437083192112">"USB for photo transfer"</string>
<string name="usb_midi_notification_title" msgid="4850904915889144654">"USB for MIDI"</string>
@@ -1060,11 +1061,10 @@
<string name="share_remote_bugreport_action" msgid="6249476773913384948">"SHARE"</string>
<string name="decline_remote_bugreport_action" msgid="6230987241608770062">"DECLINE"</string>
<string name="select_input_method" msgid="8547250819326693584">"Change keyboard"</string>
- <string name="configure_input_methods" msgid="5673193194563164021">"Other keyboards"</string>
<string name="show_ime" msgid="2506087537466597099">"Keep it on screen while physical keyboard is active"</string>
<string name="hardware" msgid="194658061510127999">"Show virtual keyboard"</string>
- <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Select keyboard layout"</string>
- <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Touch to select a keyboard layout."</string>
+ <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Configure physical keyboard"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Tap to select language and layout"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"candidates"</u></string>
diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml
index 335f1f0..b94222c 100644
--- a/core/res/res/values-en-rIN/strings.xml
+++ b/core/res/res/values-en-rIN/strings.xml
@@ -233,8 +233,8 @@
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Contents hidden by policy"</string>
<string name="safeMode" msgid="2788228061547930246">"Safe mode"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android system"</string>
- <string name="user_owner_label" msgid="2804351898001038951">"Personal"</string>
- <string name="managed_profile_label" msgid="6260850669674791528">"Work"</string>
+ <string name="user_owner_label" msgid="1119010402169916617">"Switch to Personal"</string>
+ <string name="managed_profile_label" msgid="5289992269827577857">"Switch to Work"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"Contacts"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"access your contacts"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"Location"</string>
@@ -1045,7 +1045,8 @@
<string name="no_permissions" msgid="7283357728219338112">"No permission required"</string>
<string name="perm_costs_money" msgid="4902470324142151116">"this may cost you money"</string>
<string name="dlg_ok" msgid="7376953167039865701">"OK"</string>
- <string name="usb_charging_notification_title" msgid="4004114449249406402">"USB for charging"</string>
+ <string name="usb_charging_notification_title" msgid="6895185153353640787">"USB charging this device"</string>
+ <string name="usb_supplying_notification_title" msgid="5310642257296510271">"USB supplying power to attached device"</string>
<string name="usb_mtp_notification_title" msgid="8396264943589760855">"USB for file transfer"</string>
<string name="usb_ptp_notification_title" msgid="1347328437083192112">"USB for photo transfer"</string>
<string name="usb_midi_notification_title" msgid="4850904915889144654">"USB for MIDI"</string>
@@ -1060,11 +1061,10 @@
<string name="share_remote_bugreport_action" msgid="6249476773913384948">"SHARE"</string>
<string name="decline_remote_bugreport_action" msgid="6230987241608770062">"DECLINE"</string>
<string name="select_input_method" msgid="8547250819326693584">"Change keyboard"</string>
- <string name="configure_input_methods" msgid="5673193194563164021">"Other keyboards"</string>
<string name="show_ime" msgid="2506087537466597099">"Keep it on screen while physical keyboard is active"</string>
<string name="hardware" msgid="194658061510127999">"Show virtual keyboard"</string>
- <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Select keyboard layout"</string>
- <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Touch to select a keyboard layout."</string>
+ <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Configure physical keyboard"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Tap to select language and layout"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"candidates"</u></string>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index 27cd9d2..0bfb9e0 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -233,8 +233,8 @@
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Contenido oculto debido a la política"</string>
<string name="safeMode" msgid="2788228061547930246">"Modo seguro"</string>
<string name="android_system_label" msgid="6577375335728551336">"Sistema Android"</string>
- <string name="user_owner_label" msgid="2804351898001038951">"Personal"</string>
- <string name="managed_profile_label" msgid="6260850669674791528">"Trabajo"</string>
+ <string name="user_owner_label" msgid="1119010402169916617">"Cambiar al perfil personal"</string>
+ <string name="managed_profile_label" msgid="5289992269827577857">"Cambiar al perfil de trabajo"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"Contactos"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"acceder a los contactos"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"Ubicación"</string>
@@ -1045,7 +1045,8 @@
<string name="no_permissions" msgid="7283357728219338112">"No se requieren permisos"</string>
<string name="perm_costs_money" msgid="4902470324142151116">"esto puede costarte dinero"</string>
<string name="dlg_ok" msgid="7376953167039865701">"Aceptar"</string>
- <string name="usb_charging_notification_title" msgid="4004114449249406402">"USB solo para realizar cargas"</string>
+ <string name="usb_charging_notification_title" msgid="6895185153353640787">"Este dispositivo se está cargando mediante USB"</string>
+ <string name="usb_supplying_notification_title" msgid="5310642257296510271">"El dispositivo conectado se está cargando mediante USB"</string>
<string name="usb_mtp_notification_title" msgid="8396264943589760855">"USB para transferir archivos"</string>
<string name="usb_ptp_notification_title" msgid="1347328437083192112">"USB para transferir fotos"</string>
<string name="usb_midi_notification_title" msgid="4850904915889144654">"USB para MIDI"</string>
@@ -1060,11 +1061,10 @@
<string name="share_remote_bugreport_action" msgid="6249476773913384948">"COMPARTIR"</string>
<string name="decline_remote_bugreport_action" msgid="6230987241608770062">"RECHAZAR"</string>
<string name="select_input_method" msgid="8547250819326693584">"Cambiar el teclado"</string>
- <string name="configure_input_methods" msgid="5673193194563164021">"Otros teclados"</string>
<string name="show_ime" msgid="2506087537466597099">"Mantener en la pantalla cuando el teclado físico está activo"</string>
<string name="hardware" msgid="194658061510127999">"Mostrar teclado virtual"</string>
- <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Selecciona un diseño de teclado"</string>
- <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Toca para seleccionar un diseño de teclado."</string>
+ <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Configura el teclado físico"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Presiona para seleccionar el idioma y el diseño"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"candidatos"</u></string>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index 6521cca..99202ab 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -233,8 +233,8 @@
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Contenidos ocultos por política"</string>
<string name="safeMode" msgid="2788228061547930246">"Modo seguro"</string>
<string name="android_system_label" msgid="6577375335728551336">"Sistema Android"</string>
- <string name="user_owner_label" msgid="2804351898001038951">"Personal"</string>
- <string name="managed_profile_label" msgid="6260850669674791528">"Trabajo"</string>
+ <string name="user_owner_label" msgid="1119010402169916617">"Cambiar a perfil personal"</string>
+ <string name="managed_profile_label" msgid="5289992269827577857">"Cambiar a perfil de trabajo"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"Contactos"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"acceder a tus contactos"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"Ubicación"</string>
@@ -1045,7 +1045,8 @@
<string name="no_permissions" msgid="7283357728219338112">"No es necesario ningún permiso"</string>
<string name="perm_costs_money" msgid="4902470324142151116">"es posible que esto te cueste dinero"</string>
<string name="dlg_ok" msgid="7376953167039865701">"Aceptar"</string>
- <string name="usb_charging_notification_title" msgid="4004114449249406402">"USB para cargar"</string>
+ <string name="usb_charging_notification_title" msgid="6895185153353640787">"Cargando este dispositivo por USB"</string>
+ <string name="usb_supplying_notification_title" msgid="5310642257296510271">"El dispositivo conectado recibe la alimentación por USB"</string>
<string name="usb_mtp_notification_title" msgid="8396264943589760855">"USB para transferir archivos"</string>
<string name="usb_ptp_notification_title" msgid="1347328437083192112">"USB para transferir fotos"</string>
<string name="usb_midi_notification_title" msgid="4850904915889144654">"USB para MIDI"</string>
@@ -1060,11 +1061,10 @@
<string name="share_remote_bugreport_action" msgid="6249476773913384948">"COMPARTIR"</string>
<string name="decline_remote_bugreport_action" msgid="6230987241608770062">"RECHAZAR"</string>
<string name="select_input_method" msgid="8547250819326693584">"Cambiar teclado"</string>
- <string name="configure_input_methods" msgid="5673193194563164021">"Otros teclados"</string>
<string name="show_ime" msgid="2506087537466597099">"Debe seguir en pantalla mientras el teclado físico esté activo"</string>
<string name="hardware" msgid="194658061510127999">"Mostrar teclado virtual"</string>
- <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Selecciona un diseño de teclado"</string>
- <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Toca para seleccionar un diseño de teclado."</string>
+ <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Configura el teclado físico"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Toca para seleccionar el idioma y el diseño"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"candidatos"</u></string>
diff --git a/core/res/res/values-et-rEE/strings.xml b/core/res/res/values-et-rEE/strings.xml
index 3905a55..b1cc971 100644
--- a/core/res/res/values-et-rEE/strings.xml
+++ b/core/res/res/values-et-rEE/strings.xml
@@ -233,8 +233,8 @@
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Sisu on eeskirjadega peidetud"</string>
<string name="safeMode" msgid="2788228061547930246">"Turvarežiim"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android-süsteem"</string>
- <string name="user_owner_label" msgid="2804351898001038951">"Isiklik"</string>
- <string name="managed_profile_label" msgid="6260850669674791528">"Töö"</string>
+ <string name="user_owner_label" msgid="1119010402169916617">"Lülita isiklikule profiilile"</string>
+ <string name="managed_profile_label" msgid="5289992269827577857">"Lülita tööprofiilile"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"Kontaktid"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"juurdepääs kontaktidele"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"Asukoht"</string>
@@ -1045,7 +1045,8 @@
<string name="no_permissions" msgid="7283357728219338112">"Lube pole vaja"</string>
<string name="perm_costs_money" msgid="4902470324142151116">"see võib olla tasuline"</string>
<string name="dlg_ok" msgid="7376953167039865701">"OK"</string>
- <string name="usb_charging_notification_title" msgid="4004114449249406402">"USB laadimiseks"</string>
+ <string name="usb_charging_notification_title" msgid="6895185153353640787">"Laadimiseks ühendage USB"</string>
+ <string name="usb_supplying_notification_title" msgid="5310642257296510271">"Ühendatud seade saab toidet USB kaudu"</string>
<string name="usb_mtp_notification_title" msgid="8396264943589760855">"USB failide edastamiseks"</string>
<string name="usb_ptp_notification_title" msgid="1347328437083192112">"USB fotode edastamiseks"</string>
<string name="usb_midi_notification_title" msgid="4850904915889144654">"USB MIDI jaoks"</string>
@@ -1060,11 +1061,10 @@
<string name="share_remote_bugreport_action" msgid="6249476773913384948">"JAGA"</string>
<string name="decline_remote_bugreport_action" msgid="6230987241608770062">"KEELDU"</string>
<string name="select_input_method" msgid="8547250819326693584">"Klaviatuuri muutmine"</string>
- <string name="configure_input_methods" msgid="5673193194563164021">"Muud klaviatuurid"</string>
<string name="show_ime" msgid="2506087537466597099">"Hoia seda ekraanil, kui füüsiline klaviatuur on aktiivne"</string>
<string name="hardware" msgid="194658061510127999">"Virtuaalse klaviatuuri kuvam."</string>
- <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Klaviatuuri paigutuse valimine"</string>
- <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Puudutage klaviatuuri paigutuse valimiseks."</string>
+ <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Füüsilise klaviatuuri seadistamine"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Puudutage keele ja paigutuse valimiseks"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSŠZŽTUVWÕÄÖÜXY"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSŠZŽTUVWÕÄÖÜXY"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"kandidaadid"</u></string>
diff --git a/core/res/res/values-eu-rES/strings.xml b/core/res/res/values-eu-rES/strings.xml
index 8b8f29f..a8e0285 100644
--- a/core/res/res/values-eu-rES/strings.xml
+++ b/core/res/res/values-eu-rES/strings.xml
@@ -233,8 +233,8 @@
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Gidalerro batzuk ezkutatu dira, gidalerroei jarraiki"</string>
<string name="safeMode" msgid="2788228061547930246">"Modu segurua"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android sistema"</string>
- <string name="user_owner_label" msgid="2804351898001038951">"Pertsonalak"</string>
- <string name="managed_profile_label" msgid="6260850669674791528">"Lana"</string>
+ <string name="user_owner_label" msgid="1119010402169916617">"Aldatu profil pertsonalera"</string>
+ <string name="managed_profile_label" msgid="5289992269827577857">"Aldatu laneko profilera"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"Kontaktuak"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"kontaktuak atzitzeko"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"Kokapena"</string>
@@ -1045,7 +1045,8 @@
<string name="no_permissions" msgid="7283357728219338112">"Ez da baimenik behar"</string>
<string name="perm_costs_money" msgid="4902470324142151116">"dirua kosta dakizuke"</string>
<string name="dlg_ok" msgid="7376953167039865701">"Ados"</string>
- <string name="usb_charging_notification_title" msgid="4004114449249406402">"Kargatzeko USBa"</string>
+ <string name="usb_charging_notification_title" msgid="6895185153353640787">"Gailua USB bidez ari da kargatzen"</string>
+ <string name="usb_supplying_notification_title" msgid="5310642257296510271">"Konektatutako gailua USB bidez jasotzen ari da energia"</string>
<string name="usb_mtp_notification_title" msgid="8396264943589760855">"Fitxategiak transferitzeko USBa"</string>
<string name="usb_ptp_notification_title" msgid="1347328437083192112">"Argazkiak transferitzeko USBa"</string>
<string name="usb_midi_notification_title" msgid="4850904915889144654">"MIDI modurako USBa"</string>
@@ -1060,11 +1061,10 @@
<string name="share_remote_bugreport_action" msgid="6249476773913384948">"PARTEKATU"</string>
<string name="decline_remote_bugreport_action" msgid="6230987241608770062">"BAZTERTU"</string>
<string name="select_input_method" msgid="8547250819326693584">"Aldatu teklatua"</string>
- <string name="configure_input_methods" msgid="5673193194563164021">"Beste teklatu batzuk"</string>
<string name="show_ime" msgid="2506087537466597099">"Erakutsi pantailan teklatu fisikoa aktibo dagoen bitartean"</string>
<string name="hardware" msgid="194658061510127999">"Erakutsi teklatu birtuala"</string>
- <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Hautatu teklatuaren diseinua"</string>
- <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Ukitu teklatuaren diseinua hautatzeko."</string>
+ <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Konfiguratu teklatua fisikoa"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Hizkuntza eta diseinua hautatzeko, sakatu hau"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"hautagaiak"</u></string>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index e67e058..df9d78f 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -233,8 +233,8 @@
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"محتوا بر اساس خطمشی پنهان شده است"</string>
<string name="safeMode" msgid="2788228061547930246">"حالت ایمن"</string>
<string name="android_system_label" msgid="6577375335728551336">"سیستم Android"</string>
- <string name="user_owner_label" msgid="2804351898001038951">"شخصی"</string>
- <string name="managed_profile_label" msgid="6260850669674791528">"محل کار"</string>
+ <string name="user_owner_label" msgid="1119010402169916617">"رفتن به نمایه شخصی"</string>
+ <string name="managed_profile_label" msgid="5289992269827577857">"رفتن به نمایه کاری"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"مخاطبین"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"دسترسی به مخاطبین شما"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"مکان"</string>
@@ -1045,7 +1045,8 @@
<string name="no_permissions" msgid="7283357728219338112">"مجوزی لازم نیست"</string>
<string name="perm_costs_money" msgid="4902470324142151116">"ممکن است برای شما هزینه داشته باشد"</string>
<string name="dlg_ok" msgid="7376953167039865701">"تأیید"</string>
- <string name="usb_charging_notification_title" msgid="4004114449249406402">"USB برای شارژ کردن"</string>
+ <string name="usb_charging_notification_title" msgid="6895185153353640787">"شارژ کردن این دستگاه از طریق USB"</string>
+ <string name="usb_supplying_notification_title" msgid="5310642257296510271">"شارژ دستگاه متصل از طریق USB"</string>
<string name="usb_mtp_notification_title" msgid="8396264943589760855">"USB برای انتقال فایل"</string>
<string name="usb_ptp_notification_title" msgid="1347328437083192112">"USB برای انتقال عکس"</string>
<string name="usb_midi_notification_title" msgid="4850904915889144654">"USB برای MIDI"</string>
@@ -1060,11 +1061,10 @@
<string name="share_remote_bugreport_action" msgid="6249476773913384948">"اشتراکگذاری"</string>
<string name="decline_remote_bugreport_action" msgid="6230987241608770062">"نپذیرفتن"</string>
<string name="select_input_method" msgid="8547250819326693584">"تغییر صفحهکلید"</string>
- <string name="configure_input_methods" msgid="5673193194563164021">"صفحهکلیدهای دیگر"</string>
<string name="show_ime" msgid="2506087537466597099">"وقتی صفحهکلید فیزیکی فعال است این ویرایشگر را روی صفحه نگهمیدارد"</string>
<string name="hardware" msgid="194658061510127999">"نمایش صفحهکلید مجازی"</string>
- <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"انتخاب طرحبندی صفحهکلید"</string>
- <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"برای انتخاب یک طرحبندی صفحهکلید لمس کنید…"</string>
+ <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"پیکربندی صفحهکلید فیزیکی"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"برای انتخاب زبان و چیدمان ضربه بزنید"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"داوطلبین"</u></string>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index b1ad7e7..c869961 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -233,8 +233,8 @@
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Sisältö on piilotettu käytännön perusteella."</string>
<string name="safeMode" msgid="2788228061547930246">"Suojattu tila"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android-järjestelmä"</string>
- <string name="user_owner_label" msgid="2804351898001038951">"Henkilökoht."</string>
- <string name="managed_profile_label" msgid="6260850669674791528">"Työ"</string>
+ <string name="user_owner_label" msgid="1119010402169916617">"Siirry henkilökohtaiseen profiiliin"</string>
+ <string name="managed_profile_label" msgid="5289992269827577857">"Siirry työprofiiliin"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"Kontaktit"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"käyttää yhteystietoja"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"Sijainti"</string>
@@ -1045,7 +1045,8 @@
<string name="no_permissions" msgid="7283357728219338112">"Lupia ei tarvita"</string>
<string name="perm_costs_money" msgid="4902470324142151116">"tämä voi maksaa"</string>
<string name="dlg_ok" msgid="7376953167039865701">"OK"</string>
- <string name="usb_charging_notification_title" msgid="4004114449249406402">"USB on lataustilassa"</string>
+ <string name="usb_charging_notification_title" msgid="6895185153353640787">"Laitetta ladataan USB-yhteyden kautta"</string>
+ <string name="usb_supplying_notification_title" msgid="5310642257296510271">"Liitetty laite saa virtaa USB-yhteyden kautta"</string>
<string name="usb_mtp_notification_title" msgid="8396264943589760855">"USB on tiedonsiirtotilassa"</string>
<string name="usb_ptp_notification_title" msgid="1347328437083192112">"USB on kuvansiirtotilassa"</string>
<string name="usb_midi_notification_title" msgid="4850904915889144654">"USB on MIDI-tilassa"</string>
@@ -1060,11 +1061,10 @@
<string name="share_remote_bugreport_action" msgid="6249476773913384948">"JAA"</string>
<string name="decline_remote_bugreport_action" msgid="6230987241608770062">"HYLKÄÄ"</string>
<string name="select_input_method" msgid="8547250819326693584">"Vaihda näppäimistö"</string>
- <string name="configure_input_methods" msgid="5673193194563164021">"Muut näppäimistöt"</string>
<string name="show_ime" msgid="2506087537466597099">"Pidä näytöllä, kun fyysinen näppäimistö on aktiivinen."</string>
<string name="hardware" msgid="194658061510127999">"Näytä virtuaalinen näppäimistö"</string>
- <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Valitse näppäimistöasettelu"</string>
- <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Kosketa ja valitse näppäimistöasettelu."</string>
+ <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Määritä fyysinen näppäimistö"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Valitse kieli ja asettelu koskettamalla."</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZÅÄÖ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"kandidaatit"</u></string>
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index 09993ac..efc8af3 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -233,8 +233,8 @@
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Contenu masqué conformément aux politiques"</string>
<string name="safeMode" msgid="2788228061547930246">"Mode sécurisé"</string>
<string name="android_system_label" msgid="6577375335728551336">"Système Android"</string>
- <string name="user_owner_label" msgid="2804351898001038951">"Personnel"</string>
- <string name="managed_profile_label" msgid="6260850669674791528">"Travail"</string>
+ <string name="user_owner_label" msgid="1119010402169916617">"Passer au profil personnel"</string>
+ <string name="managed_profile_label" msgid="5289992269827577857">"Passer au profil professionnel"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"Contacts"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"accéder à vos contacts"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"Localisation"</string>
@@ -1045,7 +1045,8 @@
<string name="no_permissions" msgid="7283357728219338112">"Aucune autorisation requise"</string>
<string name="perm_costs_money" msgid="4902470324142151116">"cela peut engendrer des frais"</string>
<string name="dlg_ok" msgid="7376953167039865701">"OK"</string>
- <string name="usb_charging_notification_title" msgid="4004114449249406402">"USB pour la recharge"</string>
+ <string name="usb_charging_notification_title" msgid="6895185153353640787">"Cet appareil est en cours de charge par USB"</string>
+ <string name="usb_supplying_notification_title" msgid="5310642257296510271">"Un connecteur USB alimente cet appareil"</string>
<string name="usb_mtp_notification_title" msgid="8396264943589760855">"USB pour le transfert de fichiers"</string>
<string name="usb_ptp_notification_title" msgid="1347328437083192112">"USB pour le transfert de photos"</string>
<string name="usb_midi_notification_title" msgid="4850904915889144654">"USB pour MIDI"</string>
@@ -1060,11 +1061,10 @@
<string name="share_remote_bugreport_action" msgid="6249476773913384948">"PARTAGER"</string>
<string name="decline_remote_bugreport_action" msgid="6230987241608770062">"REFUSER"</string>
<string name="select_input_method" msgid="8547250819326693584">"Changer de clavier"</string>
- <string name="configure_input_methods" msgid="5673193194563164021">"Autres claviers"</string>
<string name="show_ime" msgid="2506087537466597099">"Afficher lorsque le clavier physique est activé"</string>
<string name="hardware" msgid="194658061510127999">"Afficher le clavier virtuel"</string>
- <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Sélectionnez la disposition du clavier"</string>
- <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Appuyez ici pour sélectionner une disposition de clavier."</string>
+ <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Configurer le clavier physique"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Touchez pour sélectionner la langue et la configuration du clavier"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"candidats"</u></string>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index 30ff9fb..4e83fa9 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -233,8 +233,8 @@
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Contenu masqué conformément aux règles"</string>
<string name="safeMode" msgid="2788228061547930246">"Mode sécurisé"</string>
<string name="android_system_label" msgid="6577375335728551336">"Système Android"</string>
- <string name="user_owner_label" msgid="2804351898001038951">"Personnel"</string>
- <string name="managed_profile_label" msgid="6260850669674791528">"Professionnel"</string>
+ <string name="user_owner_label" msgid="1119010402169916617">"Passer au profil personnel"</string>
+ <string name="managed_profile_label" msgid="5289992269827577857">"Passer au profil professionnel"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"Contacts"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"accéder à vos contacts"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"Position"</string>
@@ -1045,7 +1045,8 @@
<string name="no_permissions" msgid="7283357728219338112">"Aucune autorisation requise"</string>
<string name="perm_costs_money" msgid="4902470324142151116">"Cela peut engendrer des frais"</string>
<string name="dlg_ok" msgid="7376953167039865701">"OK"</string>
- <string name="usb_charging_notification_title" msgid="4004114449249406402">"Recharge par USB"</string>
+ <string name="usb_charging_notification_title" msgid="6895185153353640787">"Recharge via USB de cet appareil…"</string>
+ <string name="usb_supplying_notification_title" msgid="5310642257296510271">"Alimentation via USB de l\'appareil connecté…"</string>
<string name="usb_mtp_notification_title" msgid="8396264943589760855">"USB pour le transfert de fichiers"</string>
<string name="usb_ptp_notification_title" msgid="1347328437083192112">"USB pour le transfert de photos"</string>
<string name="usb_midi_notification_title" msgid="4850904915889144654">"USB en mode MIDI"</string>
@@ -1060,11 +1061,10 @@
<string name="share_remote_bugreport_action" msgid="6249476773913384948">"PARTAGER"</string>
<string name="decline_remote_bugreport_action" msgid="6230987241608770062">"REFUSER"</string>
<string name="select_input_method" msgid="8547250819326693584">"Changer de clavier"</string>
- <string name="configure_input_methods" msgid="5673193194563164021">"Autres claviers"</string>
<string name="show_ime" msgid="2506087537466597099">"Afficher lorsque le clavier physique est activé"</string>
<string name="hardware" msgid="194658061510127999">"Afficher le clavier virtuel"</string>
- <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Sélectionnez la disposition du clavier"</string>
- <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Appuyez ici pour sélectionner une disposition de clavier."</string>
+ <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Configurer le clavier physique"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Appuyer pour sélectionner la langue et la disposition"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"candidats"</u></string>
diff --git a/core/res/res/values-gl-rES/strings.xml b/core/res/res/values-gl-rES/strings.xml
index 0d479a5..2fa6087 100644
--- a/core/res/res/values-gl-rES/strings.xml
+++ b/core/res/res/values-gl-rES/strings.xml
@@ -233,8 +233,8 @@
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Ocultouse contido por causa da política"</string>
<string name="safeMode" msgid="2788228061547930246">"Modo seguro"</string>
<string name="android_system_label" msgid="6577375335728551336">"Sistema Android"</string>
- <string name="user_owner_label" msgid="2804351898001038951">"Persoal"</string>
- <string name="managed_profile_label" msgid="6260850669674791528">"Traballo"</string>
+ <string name="user_owner_label" msgid="1119010402169916617">"Cambiar ao perfil persoal"</string>
+ <string name="managed_profile_label" msgid="5289992269827577857">"Cambiar ao perfil de traballo"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"Contactos"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"acceder aos teus contactos"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"Localización"</string>
@@ -1045,7 +1045,8 @@
<string name="no_permissions" msgid="7283357728219338112">"Non é necesario ningún permiso"</string>
<string name="perm_costs_money" msgid="4902470324142151116">"é posible que teñas que pagar"</string>
<string name="dlg_ok" msgid="7376953167039865701">"Aceptar"</string>
- <string name="usb_charging_notification_title" msgid="4004114449249406402">"USB para carga"</string>
+ <string name="usb_charging_notification_title" msgid="6895185153353640787">"O USB está cargando este dispositivo"</string>
+ <string name="usb_supplying_notification_title" msgid="5310642257296510271">"O USB está proporcionando enerxía ao dispositivo conectado"</string>
<string name="usb_mtp_notification_title" msgid="8396264943589760855">"USB para transferencia de ficheiros"</string>
<string name="usb_ptp_notification_title" msgid="1347328437083192112">"USB para transferencia de fotos"</string>
<string name="usb_midi_notification_title" msgid="4850904915889144654">"USB para MIDI"</string>
@@ -1060,11 +1061,10 @@
<string name="share_remote_bugreport_action" msgid="6249476773913384948">"COMPARTIR"</string>
<string name="decline_remote_bugreport_action" msgid="6230987241608770062">"ANULAR"</string>
<string name="select_input_method" msgid="8547250819326693584">"Cambiar teclado"</string>
- <string name="configure_input_methods" msgid="5673193194563164021">"Outros teclados"</string>
<string name="show_ime" msgid="2506087537466597099">"Manteno na pantalla mentres o teclado físico estea activo"</string>
<string name="hardware" msgid="194658061510127999">"Mostrar teclado virtual"</string>
- <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Seleccionar deseño de teclado"</string>
- <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Toca para seleccionar un deseño de teclado."</string>
+ <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Configura o teclado físico"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Toca para seleccionar o idioma e o deseño"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNÑOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNÑOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"candidatos"</u></string>
diff --git a/core/res/res/values-gu-rIN/strings.xml b/core/res/res/values-gu-rIN/strings.xml
index 4389cff..0b9f4ad 100644
--- a/core/res/res/values-gu-rIN/strings.xml
+++ b/core/res/res/values-gu-rIN/strings.xml
@@ -233,8 +233,8 @@
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"નીતિ દ્વારા સામગ્રી છુપાવાઈ"</string>
<string name="safeMode" msgid="2788228061547930246">"સુરક્ષિત મોડ"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android સિસ્ટમ"</string>
- <string name="user_owner_label" msgid="2804351898001038951">"વ્યક્તિગત"</string>
- <string name="managed_profile_label" msgid="6260850669674791528">"કાર્યાલય"</string>
+ <string name="user_owner_label" msgid="1119010402169916617">"વ્યક્તિગત પર સ્વિચ કરો"</string>
+ <string name="managed_profile_label" msgid="5289992269827577857">"કાર્ય પર સ્વિચ કરો"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"સંપર્કો"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"તમારા સંપર્કોને ઍક્સેસ કરો"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"સ્થાન"</string>
@@ -1045,7 +1045,8 @@
<string name="no_permissions" msgid="7283357728219338112">"કોઈ પરવાનગીઓ જરૂરી નથી"</string>
<string name="perm_costs_money" msgid="4902470324142151116">"આનાથી તમારા પૈસા ખર્ચ થઈ શકે છે"</string>
<string name="dlg_ok" msgid="7376953167039865701">"ઑકે"</string>
- <string name="usb_charging_notification_title" msgid="4004114449249406402">"ચાર્જ કરવા માટે USB"</string>
+ <string name="usb_charging_notification_title" msgid="6895185153353640787">"આ ઉપકરણને USB થી ચાર્જ કરે છે"</string>
+ <string name="usb_supplying_notification_title" msgid="5310642257296510271">"જોડાયેલ ઉપકરણ માટે USB પાવર પૂરો પાડે છે"</string>
<string name="usb_mtp_notification_title" msgid="8396264943589760855">"ફાઇલ ટ્રાન્સફર માટે USB"</string>
<string name="usb_ptp_notification_title" msgid="1347328437083192112">"ફોટા ટ્રાન્સફર માટે USB"</string>
<string name="usb_midi_notification_title" msgid="4850904915889144654">"MIDI માટે USB"</string>
@@ -1060,11 +1061,10 @@
<string name="share_remote_bugreport_action" msgid="6249476773913384948">"શેર કરો"</string>
<string name="decline_remote_bugreport_action" msgid="6230987241608770062">"નકારો"</string>
<string name="select_input_method" msgid="8547250819326693584">"કીબોર્ડ બદલો"</string>
- <string name="configure_input_methods" msgid="5673193194563164021">"અન્ય કીબોર્ડ્સ"</string>
<string name="show_ime" msgid="2506087537466597099">"જ્યારે ભૌતિક કીબોર્ડ સક્રિય હોય ત્યારે તેને સ્ક્રીન પર રાખો"</string>
<string name="hardware" msgid="194658061510127999">"વર્ચ્યુઅલ કીબોર્ડ બતાવો"</string>
- <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"કીબોર્ડ લેઆઉટ પસંદ કરો."</string>
- <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"કીબોર્ડ લેઆઉટ પસંદ કરવા માટે ટચ કરો."</string>
+ <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"ભૌતિક કીબોર્ડ ગોઠવો"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"ભાષા અને લેઆઉટ પસંદ કરવા માટે ટૅપ કરો"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"ઉમેદવારો"</u></string>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index 18c4007..474e81e 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -233,8 +233,8 @@
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"सामग्री पॉलिसी के द्वारा छिपी हुई है"</string>
<string name="safeMode" msgid="2788228061547930246">"सुरक्षित मोड"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android सिस्टम"</string>
- <string name="user_owner_label" msgid="2804351898001038951">"व्यक्तिगत"</string>
- <string name="managed_profile_label" msgid="6260850669674791528">"कार्यालय"</string>
+ <string name="user_owner_label" msgid="1119010402169916617">"व्यक्तिगत प्रोफ़ाइल में स्विच करें"</string>
+ <string name="managed_profile_label" msgid="5289992269827577857">"कार्य प्रोफ़ाइल में स्विच करें"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"संपर्क"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"अपने संपर्कों को ऐक्सेस करें"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"स्थान"</string>
@@ -1045,7 +1045,8 @@
<string name="no_permissions" msgid="7283357728219338112">"किसी अनुमति की आवश्यकता नहीं है"</string>
<string name="perm_costs_money" msgid="4902470324142151116">"इससे आपको धन देना पड़ सकता है"</string>
<string name="dlg_ok" msgid="7376953167039865701">"ठीक है"</string>
- <string name="usb_charging_notification_title" msgid="4004114449249406402">"चार्जिंग के लिए USB"</string>
+ <string name="usb_charging_notification_title" msgid="6895185153353640787">"यह डिवाइस USB से चार्ज हो रहा है"</string>
+ <string name="usb_supplying_notification_title" msgid="5310642257296510271">"अटैच किए गए डिवाइस को USB से पावर मिल रही है"</string>
<string name="usb_mtp_notification_title" msgid="8396264943589760855">"फ़ाइल स्थानांतरण के लिए USB"</string>
<string name="usb_ptp_notification_title" msgid="1347328437083192112">"फ़ोटो स्थानांतरण के लिए USB"</string>
<string name="usb_midi_notification_title" msgid="4850904915889144654">"MIDI के लिए USB"</string>
@@ -1060,11 +1061,10 @@
<string name="share_remote_bugreport_action" msgid="6249476773913384948">"साझा करें"</string>
<string name="decline_remote_bugreport_action" msgid="6230987241608770062">"अस्वीकार करें"</string>
<string name="select_input_method" msgid="8547250819326693584">"कीबोर्ड बदलें"</string>
- <string name="configure_input_methods" msgid="5673193194563164021">"अन्य कीबोर्ड"</string>
<string name="show_ime" msgid="2506087537466597099">"भौतिक कीबोर्ड के सक्रिय होने के दौरान इसे स्क्रीन पर बनाए रखें"</string>
<string name="hardware" msgid="194658061510127999">"वर्चुअल कीबोर्ड दिखाएं"</string>
- <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"कीबोर्ड लेआउट को चुनें"</string>
- <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"कीबोर्ड लेआउट का चयन करने के लिए स्पर्श करें."</string>
+ <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"भौतिक कीबोर्ड कॉन्फ़िगर करें"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"भाषा और लेआउट चुनने के लिए टैप करें"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"उम्मीदवार"</u></string>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index bc74c9d..837aa56 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -235,8 +235,8 @@
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Sadržaj je skriven prema pravilima"</string>
<string name="safeMode" msgid="2788228061547930246">"Siguran način rada"</string>
<string name="android_system_label" msgid="6577375335728551336">"Sustav Android"</string>
- <string name="user_owner_label" msgid="2804351898001038951">"Osobno"</string>
- <string name="managed_profile_label" msgid="6260850669674791528">"Posao"</string>
+ <string name="user_owner_label" msgid="1119010402169916617">"Prijeđite na osobni"</string>
+ <string name="managed_profile_label" msgid="5289992269827577857">"Prijeđite na radni"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"Kontakti"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"pristupati vašim kontaktima"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"Lokacija"</string>
@@ -1053,7 +1053,8 @@
<string name="no_permissions" msgid="7283357728219338112">"Nije potrebno dopuštenje"</string>
<string name="perm_costs_money" msgid="4902470324142151116">"možda ćete morati platiti"</string>
<string name="dlg_ok" msgid="7376953167039865701">"U redu"</string>
- <string name="usb_charging_notification_title" msgid="4004114449249406402">"USB za punjenje"</string>
+ <string name="usb_charging_notification_title" msgid="6895185153353640787">"Punjenje uređaja USB-om"</string>
+ <string name="usb_supplying_notification_title" msgid="5310642257296510271">"Napajanje priključenog uređaja USB-om"</string>
<string name="usb_mtp_notification_title" msgid="8396264943589760855">"USB za prijenos datoteka"</string>
<string name="usb_ptp_notification_title" msgid="1347328437083192112">"USB za prijenos fotografija"</string>
<string name="usb_midi_notification_title" msgid="4850904915889144654">"USB za MIDI"</string>
@@ -1068,11 +1069,10 @@
<string name="share_remote_bugreport_action" msgid="6249476773913384948">"DIJELI"</string>
<string name="decline_remote_bugreport_action" msgid="6230987241608770062">"ODBIJ"</string>
<string name="select_input_method" msgid="8547250819326693584">"Promjena tipkovnice"</string>
- <string name="configure_input_methods" msgid="5673193194563164021">"Ostale tipkovnice"</string>
<string name="show_ime" msgid="2506087537466597099">"Zadržava se na zaslonu dok je fizička tipkovnica aktivna"</string>
<string name="hardware" msgid="194658061510127999">"Prikaži virtualnu tipkovnicu"</string>
- <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Odaberite izgled tipkovnice"</string>
- <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Dodirnite za odabir izgleda tipkovnice."</string>
+ <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Konfigurirajte fizičku tipkovnicu"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Dodirnite da biste odabrali jezik i raspored"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"kandidati"</u></string>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index bf23b71..0c4705d 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -233,8 +233,8 @@
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"A tartalom irányelv miatt elrejtve"</string>
<string name="safeMode" msgid="2788228061547930246">"Biztonsági üzemmód"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android rendszer"</string>
- <string name="user_owner_label" msgid="2804351898001038951">"Személyes"</string>
- <string name="managed_profile_label" msgid="6260850669674791528">"Munkahelyi"</string>
+ <string name="user_owner_label" msgid="1119010402169916617">"Átváltás személyes profilra"</string>
+ <string name="managed_profile_label" msgid="5289992269827577857">"Átváltás munkaprofilra"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"Névjegyek"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"hozzáférés a névjegyekhez"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"Helyadatok"</string>
@@ -1045,7 +1045,8 @@
<string name="no_permissions" msgid="7283357728219338112">"Nincs szükség engedélyre"</string>
<string name="perm_costs_money" msgid="4902470324142151116">"ez pénzbe kerülhet Önnek"</string>
<string name="dlg_ok" msgid="7376953167039865701">"OK"</string>
- <string name="usb_charging_notification_title" msgid="4004114449249406402">"USB töltéshez"</string>
+ <string name="usb_charging_notification_title" msgid="6895185153353640787">"Az eszköz USB-s töltése"</string>
+ <string name="usb_supplying_notification_title" msgid="5310642257296510271">"A csatlakoztatott eszköz USB-n keresztül való töltése"</string>
<string name="usb_mtp_notification_title" msgid="8396264943589760855">"USB fájlátvitelhez"</string>
<string name="usb_ptp_notification_title" msgid="1347328437083192112">"USB fotóátvitelhez"</string>
<string name="usb_midi_notification_title" msgid="4850904915889144654">"USB MIDI-hez"</string>
@@ -1060,11 +1061,10 @@
<string name="share_remote_bugreport_action" msgid="6249476773913384948">"MEGOSZTÁS"</string>
<string name="decline_remote_bugreport_action" msgid="6230987241608770062">"ELUTASÍTÁS"</string>
<string name="select_input_method" msgid="8547250819326693584">"Billentyűzet megváltoztatása"</string>
- <string name="configure_input_methods" msgid="5673193194563164021">"Más billentyűzetek"</string>
<string name="show_ime" msgid="2506087537466597099">"Maradjon a képernyőn, amíg a billentyűzet aktív"</string>
<string name="hardware" msgid="194658061510127999">"Virtuális billentyűzet"</string>
- <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Válasszon billentyűzetkiosztást"</string>
- <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Érintse meg az egyik billentyűzetkiosztás kiválasztásához."</string>
+ <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Állítsa be a fizikai billentyűzetet"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Koppintson a nyelv és a billentyűzetkiosztás kiválasztásához"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"jelöltek"</u></string>
diff --git a/core/res/res/values-hy-rAM/strings.xml b/core/res/res/values-hy-rAM/strings.xml
index 030975e..4be90da 100644
--- a/core/res/res/values-hy-rAM/strings.xml
+++ b/core/res/res/values-hy-rAM/strings.xml
@@ -233,8 +233,8 @@
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Բովանդակությունը թաքցվել է ըստ քաղաքականության"</string>
<string name="safeMode" msgid="2788228061547930246">"Անվտանգ ռեժիմ"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android համակարգ"</string>
- <string name="user_owner_label" msgid="2804351898001038951">"Անձնական"</string>
- <string name="managed_profile_label" msgid="6260850669674791528">"Աշխատանքային"</string>
+ <string name="user_owner_label" msgid="1119010402169916617">"Անցնել անհատական պրոֆիլին"</string>
+ <string name="managed_profile_label" msgid="5289992269827577857">"Անցնել աշխատանքային պրոֆիլին"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"Կոնտակտներ"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"կոնտակտների հասանելիություն"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"Տեղադրություն"</string>
@@ -1045,7 +1045,8 @@
<string name="no_permissions" msgid="7283357728219338112">"Թույլտվություններ չեն պահանջվում"</string>
<string name="perm_costs_money" msgid="4902470324142151116">"Սա կարող է գումար պահանջել"</string>
<string name="dlg_ok" msgid="7376953167039865701">"Լավ"</string>
- <string name="usb_charging_notification_title" msgid="4004114449249406402">"Լիցքավորման USB"</string>
+ <string name="usb_charging_notification_title" msgid="6895185153353640787">"Սարքի լիցքավորում USB լարի միջոցով"</string>
+ <string name="usb_supplying_notification_title" msgid="5310642257296510271">"Հոսանքի մատակարարում կցված սարքերին USB լարի միջոցով"</string>
<string name="usb_mtp_notification_title" msgid="8396264943589760855">"Ֆայլերի փոխանցման USB"</string>
<string name="usb_ptp_notification_title" msgid="1347328437083192112">"Լուսանկարների փոխանցման USB"</string>
<string name="usb_midi_notification_title" msgid="4850904915889144654">"MIDI-ի USB"</string>
@@ -1060,11 +1061,10 @@
<string name="share_remote_bugreport_action" msgid="6249476773913384948">"ՏՐԱՄԱԴՐԵԼ"</string>
<string name="decline_remote_bugreport_action" msgid="6230987241608770062">"ՄԵՐԺԵԼ"</string>
<string name="select_input_method" msgid="8547250819326693584">"Փոխել ստեղնաշարը"</string>
- <string name="configure_input_methods" msgid="5673193194563164021">"Այլ ստեղնաշարեր"</string>
<string name="show_ime" msgid="2506087537466597099">"Պահել էկրանին մինչդեռ ֆիզիկական ստեղնաշարն ակտիվ է"</string>
<string name="hardware" msgid="194658061510127999">"Ցույց տալ վիրտուալ ստեղնաշարը"</string>
- <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Ընտրեք ստեղնաշարի դիրքը"</string>
- <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Հպեք` ստեղնաշարի դիրքը ընտրելու համար:"</string>
+ <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Կազմաձևեք ֆիզիկական ստեղնաշարը"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Հպեք՝ լեզուն և դասավորությունն ընտրելու համար"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ԱԲԳԴԵԶԷԸԹԺԻԼԽԾԿՀՁՂՃՄՅՆՇՈՉՊՋՌՍՎՏՐՑՈՒՓՔԵւՕՖ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"թեկնածուները"</u></string>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index 819ea80..7218617 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -233,8 +233,8 @@
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Konten disembunyikan menurut kebijakan"</string>
<string name="safeMode" msgid="2788228061547930246">"Mode aman"</string>
<string name="android_system_label" msgid="6577375335728551336">"Sistem Android"</string>
- <string name="user_owner_label" msgid="2804351898001038951">"Pribadi"</string>
- <string name="managed_profile_label" msgid="6260850669674791528">"Kantor"</string>
+ <string name="user_owner_label" msgid="1119010402169916617">"Beralih ke Pribadi"</string>
+ <string name="managed_profile_label" msgid="5289992269827577857">"Beralih ke Kantor"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"Kontak"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"mengakses kontak"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"Lokasi"</string>
@@ -1045,7 +1045,8 @@
<string name="no_permissions" msgid="7283357728219338112">"Tidak perlu izin"</string>
<string name="perm_costs_money" msgid="4902470324142151116">"ini mungkin tidak gratis"</string>
<string name="dlg_ok" msgid="7376953167039865701">"Oke"</string>
- <string name="usb_charging_notification_title" msgid="4004114449249406402">"USB untuk pengisian daya"</string>
+ <string name="usb_charging_notification_title" msgid="6895185153353640787">"Isi daya perangkat ini melalui USB"</string>
+ <string name="usb_supplying_notification_title" msgid="5310642257296510271">"Suplai daya melalui USB ke perangkat yang terpasang"</string>
<string name="usb_mtp_notification_title" msgid="8396264943589760855">"USB untuk transfer file"</string>
<string name="usb_ptp_notification_title" msgid="1347328437083192112">"USB untuk transfer foto"</string>
<string name="usb_midi_notification_title" msgid="4850904915889144654">"USB untuk MIDI"</string>
@@ -1060,11 +1061,10 @@
<string name="share_remote_bugreport_action" msgid="6249476773913384948">"BAGIKAN"</string>
<string name="decline_remote_bugreport_action" msgid="6230987241608770062">"TOLAK"</string>
<string name="select_input_method" msgid="8547250819326693584">"Ubah keyboard"</string>
- <string name="configure_input_methods" msgid="5673193194563164021">"Keyboard lainnya"</string>
<string name="show_ime" msgid="2506087537466597099">"Pertahankan di layar jika keyboard fisik masih aktif"</string>
<string name="hardware" msgid="194658061510127999">"Tampilkan keyboard virtual"</string>
- <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Pilih tata letak keyboard"</string>
- <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Sentuh untuk memilih tata letak keyboard."</string>
+ <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Mengonfigurasi keyboard fisik"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Ketuk untuk memilih bahasa dan tata letak"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"calon"</u></string>
diff --git a/core/res/res/values-is-rIS/strings.xml b/core/res/res/values-is-rIS/strings.xml
index 91624e7..cebc4cc 100644
--- a/core/res/res/values-is-rIS/strings.xml
+++ b/core/res/res/values-is-rIS/strings.xml
@@ -233,8 +233,8 @@
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Efni falið með reglu"</string>
<string name="safeMode" msgid="2788228061547930246">"Örugg stilling"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android kerfið"</string>
- <string name="user_owner_label" msgid="2804351898001038951">"Persónulegt"</string>
- <string name="managed_profile_label" msgid="6260850669674791528">"Vinna"</string>
+ <string name="user_owner_label" msgid="1119010402169916617">"Skipta yfir í persónulegt snið"</string>
+ <string name="managed_profile_label" msgid="5289992269827577857">"Skipta yfir í vinnusnið"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"Tengiliðir"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"fá aðgang að tengiliðunum þínum"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"Staðsetning"</string>
@@ -1045,7 +1045,8 @@
<string name="no_permissions" msgid="7283357728219338112">"Engra heimilda þörf"</string>
<string name="perm_costs_money" msgid="4902470324142151116">"þú gætir þurft að borga fyrir þetta"</string>
<string name="dlg_ok" msgid="7376953167039865701">"Í lagi"</string>
- <string name="usb_charging_notification_title" msgid="4004114449249406402">"USB fyrir hleðslu"</string>
+ <string name="usb_charging_notification_title" msgid="6895185153353640787">"Þetta tæki er í USB-hleðslu"</string>
+ <string name="usb_supplying_notification_title" msgid="5310642257296510271">"Tengt tæki er í USB-hleðslu"</string>
<string name="usb_mtp_notification_title" msgid="8396264943589760855">"USB fyrir skráaflutning"</string>
<string name="usb_ptp_notification_title" msgid="1347328437083192112">"USB fyrir myndaflutning"</string>
<string name="usb_midi_notification_title" msgid="4850904915889144654">"USB fyrir MIDI"</string>
@@ -1060,11 +1061,10 @@
<string name="share_remote_bugreport_action" msgid="6249476773913384948">"DEILA"</string>
<string name="decline_remote_bugreport_action" msgid="6230987241608770062">"HAFNA"</string>
<string name="select_input_method" msgid="8547250819326693584">"Skipta um lyklaborð"</string>
- <string name="configure_input_methods" msgid="5673193194563164021">"Önnur lyklaborð"</string>
<string name="show_ime" msgid="2506087537466597099">"Haltu því á skjánum meðan vélbúnaðarlyklaborðið er virkt"</string>
<string name="hardware" msgid="194658061510127999">"Sýna sýndarlyklaborð"</string>
- <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Veldu lyklaskipan"</string>
- <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Snertu til að velja lyklaskipan."</string>
+ <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Stilla vélbúnaðarlyklaborð"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Ýttu til að velja tungumál og útlit"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" AÁBCDÐEÉFGHIÍJKLMNOÓPQRSTUÚVWXYÝZÞÆÖ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789AÁBCDÐEÉFGHIÍJKLMNOÓPQRSTUÚVWXYÝZÞÆÖ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"möguleikar"</u></string>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index 9937e0d..2a73990 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -233,8 +233,8 @@
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Contenuti nascosti in base alle norme"</string>
<string name="safeMode" msgid="2788228061547930246">"Modalità provvisoria"</string>
<string name="android_system_label" msgid="6577375335728551336">"Sistema Android"</string>
- <string name="user_owner_label" msgid="2804351898001038951">"Personale"</string>
- <string name="managed_profile_label" msgid="6260850669674791528">"Lavoro"</string>
+ <string name="user_owner_label" msgid="1119010402169916617">"Passa al profilo personale"</string>
+ <string name="managed_profile_label" msgid="5289992269827577857">"Passa al profilo di lavoro"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"Contatti"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"accedere ai contatti"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"Posizione"</string>
@@ -1045,7 +1045,8 @@
<string name="no_permissions" msgid="7283357728219338112">"Nessuna autorizzazione richiesta"</string>
<string name="perm_costs_money" msgid="4902470324142151116">"potrebbe comportare dei costi"</string>
<string name="dlg_ok" msgid="7376953167039865701">"OK"</string>
- <string name="usb_charging_notification_title" msgid="4004114449249406402">"USB per la ricarica"</string>
+ <string name="usb_charging_notification_title" msgid="6895185153353640787">"Dispositivo in carica tramite USB"</string>
+ <string name="usb_supplying_notification_title" msgid="5310642257296510271">"Dispositivo collegato alimentato tramite USB"</string>
<string name="usb_mtp_notification_title" msgid="8396264943589760855">"USB per il trasferimento di file"</string>
<string name="usb_ptp_notification_title" msgid="1347328437083192112">"USB per il trasferimento di foto"</string>
<string name="usb_midi_notification_title" msgid="4850904915889144654">"USB per la modalità MIDI"</string>
@@ -1060,11 +1061,10 @@
<string name="share_remote_bugreport_action" msgid="6249476773913384948">"CONDIVIDI"</string>
<string name="decline_remote_bugreport_action" msgid="6230987241608770062">"RIFIUTO"</string>
<string name="select_input_method" msgid="8547250819326693584">"Cambia tastiera"</string>
- <string name="configure_input_methods" msgid="5673193194563164021">"Altre tastiere"</string>
<string name="show_ime" msgid="2506087537466597099">"Tieni sullo schermo quando è attiva la tastiera fisica"</string>
<string name="hardware" msgid="194658061510127999">"Mostra tastiera virtuale"</string>
- <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Seleziona layout tastiera"</string>
- <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Tocca per selezionare un layout di tastiera."</string>
+ <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Configura la tastiera fisica"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Tocca per selezionare la lingua e il layout"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"candidati"</u></string>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index 443c1be..80435b6 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -237,8 +237,8 @@
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"התוכן מוסתר על ידי המדיניות"</string>
<string name="safeMode" msgid="2788228061547930246">"מצב בטוח"</string>
<string name="android_system_label" msgid="6577375335728551336">"מערכת Android"</string>
- <string name="user_owner_label" msgid="2804351898001038951">"אישי"</string>
- <string name="managed_profile_label" msgid="6260850669674791528">"עבודה"</string>
+ <string name="user_owner_label" msgid="1119010402169916617">"עבור ל\'אישי\'"</string>
+ <string name="managed_profile_label" msgid="5289992269827577857">"עבור ל\'עבודה\'"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"אנשי קשר"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"גישה אל אנשי הקשר"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"מיקום"</string>
@@ -1061,7 +1061,8 @@
<string name="no_permissions" msgid="7283357728219338112">"לא דרושים אישורים"</string>
<string name="perm_costs_money" msgid="4902470324142151116">"פעולה זו עשויה לחייב אותך בכסף:"</string>
<string name="dlg_ok" msgid="7376953167039865701">"אישור"</string>
- <string name="usb_charging_notification_title" msgid="4004114449249406402">"USB לטעינה"</string>
+ <string name="usb_charging_notification_title" msgid="6895185153353640787">"USB טוען את המכשיר הזה"</string>
+ <string name="usb_supplying_notification_title" msgid="5310642257296510271">"USB מספק מתח למכשיר המצורף"</string>
<string name="usb_mtp_notification_title" msgid="8396264943589760855">"USB להעברת קבצים"</string>
<string name="usb_ptp_notification_title" msgid="1347328437083192112">"USB להעברת תמונות"</string>
<string name="usb_midi_notification_title" msgid="4850904915889144654">"USB ל-MIDI"</string>
@@ -1076,11 +1077,10 @@
<string name="share_remote_bugreport_action" msgid="6249476773913384948">"שתף"</string>
<string name="decline_remote_bugreport_action" msgid="6230987241608770062">"דחה"</string>
<string name="select_input_method" msgid="8547250819326693584">"שינוי מקלדת"</string>
- <string name="configure_input_methods" msgid="5673193194563164021">"מקלדות אחרות"</string>
<string name="show_ime" msgid="2506087537466597099">"השאר אותו במסך בזמן שהמקלדת הפיזית פעילה"</string>
<string name="hardware" msgid="194658061510127999">"הצג מקלדת וירטואלית"</string>
- <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"בחירת פריסת מקלדת"</string>
- <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"גע כדי לבחור פריסת מקלדת."</string>
+ <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"הגדרת מקלדת פיזית"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"הקש כדי לבחור שפה ופריסה"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"מועמדים"</u></string>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index e81beb3..394775f 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -233,8 +233,8 @@
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"ポリシーによって非表示になっているコンテンツ"</string>
<string name="safeMode" msgid="2788228061547930246">"セーフモード"</string>
<string name="android_system_label" msgid="6577375335728551336">"Androidシステム"</string>
- <string name="user_owner_label" msgid="2804351898001038951">"個人用"</string>
- <string name="managed_profile_label" msgid="6260850669674791528">"仕事用"</string>
+ <string name="user_owner_label" msgid="1119010402169916617">"個人用に切り替える"</string>
+ <string name="managed_profile_label" msgid="5289992269827577857">"仕事用に切り替える"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"連絡先"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"連絡先へのアクセス"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"位置情報"</string>
@@ -1045,7 +1045,8 @@
<string name="no_permissions" msgid="7283357728219338112">"権限の許可は必要ありません"</string>
<string name="perm_costs_money" msgid="4902470324142151116">"料金が発生する場合があります"</string>
<string name="dlg_ok" msgid="7376953167039865701">"OK"</string>
- <string name="usb_charging_notification_title" msgid="4004114449249406402">"USBを充電に使用"</string>
+ <string name="usb_charging_notification_title" msgid="6895185153353640787">"この端末を USB で充電"</string>
+ <string name="usb_supplying_notification_title" msgid="5310642257296510271">"接続した端末に USB で給電"</string>
<string name="usb_mtp_notification_title" msgid="8396264943589760855">"USBをファイル転送に使用"</string>
<string name="usb_ptp_notification_title" msgid="1347328437083192112">"USBを写真転送に使用"</string>
<string name="usb_midi_notification_title" msgid="4850904915889144654">"USBをMIDIに使用"</string>
@@ -1060,11 +1061,10 @@
<string name="share_remote_bugreport_action" msgid="6249476773913384948">"共有する"</string>
<string name="decline_remote_bugreport_action" msgid="6230987241608770062">"共有しない"</string>
<string name="select_input_method" msgid="8547250819326693584">"キーボードの変更"</string>
- <string name="configure_input_methods" msgid="5673193194563164021">"その他のキーボード"</string>
<string name="show_ime" msgid="2506087537466597099">"物理キーボードが有効になっている間は、画面に表示されます"</string>
<string name="hardware" msgid="194658061510127999">"仮想キーボードの表示"</string>
- <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"キーボードレイアウトの選択"</string>
- <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"タップしてキーボードレイアウトを選択してください。"</string>
+ <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"物理キーボードの設定"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"タップして言語とレイアウトを選択してください"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"候補"</u></string>
diff --git a/core/res/res/values-ka-rGE/strings.xml b/core/res/res/values-ka-rGE/strings.xml
index 3e463f1..fcc56da 100644
--- a/core/res/res/values-ka-rGE/strings.xml
+++ b/core/res/res/values-ka-rGE/strings.xml
@@ -233,8 +233,8 @@
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"შიგთავსი დამალულია წესების შესაბამისად"</string>
<string name="safeMode" msgid="2788228061547930246">"უსაფრთხო რეჟიმი"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android-ის სისტემა"</string>
- <string name="user_owner_label" msgid="2804351898001038951">"პირადი"</string>
- <string name="managed_profile_label" msgid="6260850669674791528">"სამსახური"</string>
+ <string name="user_owner_label" msgid="1119010402169916617">"პირად პროფილზე გადართვა"</string>
+ <string name="managed_profile_label" msgid="5289992269827577857">"სამსახურის პროფილზე გადართვა"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"კონტაქტები"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"თქვენს კონტაქტებზე წვდომა"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"მდებარეობა"</string>
@@ -1045,7 +1045,8 @@
<string name="no_permissions" msgid="7283357728219338112">"ნებართვა საჭირო არ არის"</string>
<string name="perm_costs_money" msgid="4902470324142151116">"ამისათვის შესაძლოა მოგიწიოთ თანხის გადახდა"</string>
<string name="dlg_ok" msgid="7376953167039865701">"OK"</string>
- <string name="usb_charging_notification_title" msgid="4004114449249406402">"USB დამუხტვისთვის"</string>
+ <string name="usb_charging_notification_title" msgid="6895185153353640787">"მოწყობილობა USB-ის მეშვეობით იტენება"</string>
+ <string name="usb_supplying_notification_title" msgid="5310642257296510271">"მიერთებულ მოწყობილობას ელკვებას USB აწვდის"</string>
<string name="usb_mtp_notification_title" msgid="8396264943589760855">"USB ფაილების გადაცემისთვის"</string>
<string name="usb_ptp_notification_title" msgid="1347328437083192112">"USB ფოტოების გადაცემისთვის"</string>
<string name="usb_midi_notification_title" msgid="4850904915889144654">"USB MIDI-სთვის"</string>
@@ -1060,11 +1061,10 @@
<string name="share_remote_bugreport_action" msgid="6249476773913384948">"გაზიარება"</string>
<string name="decline_remote_bugreport_action" msgid="6230987241608770062">"უარყოფა"</string>
<string name="select_input_method" msgid="8547250819326693584">"კლავიატურის შეცვლა"</string>
- <string name="configure_input_methods" msgid="5673193194563164021">"სხვა კლავიატურები"</string>
<string name="show_ime" msgid="2506087537466597099">"აქტიური ფიზიკური კლავიატურისას ეკრანზე შენარჩუნება"</string>
<string name="hardware" msgid="194658061510127999">"ვირტუალური კლავიატურის ჩვენება"</string>
- <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"შეარჩიეთ კლავიატურის განლაგება."</string>
- <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"კლავიატურის განლაგების შესარჩევად შეეხეთ."</string>
+ <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"მოახდინეთ ფიზიკური კლავიატურის კონფიგურაცია"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"შეეხეთ ენისა და განლაგების ასარჩევად"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"კანდიდატები"</u></string>
diff --git a/core/res/res/values-kk-rKZ/strings.xml b/core/res/res/values-kk-rKZ/strings.xml
index 342db02..6eaa770 100644
--- a/core/res/res/values-kk-rKZ/strings.xml
+++ b/core/res/res/values-kk-rKZ/strings.xml
@@ -233,8 +233,8 @@
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Мазмұн саясатқа сай жасырылған"</string>
<string name="safeMode" msgid="2788228061547930246">"Қауіпсіз режим"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android жүйесі"</string>
- <string name="user_owner_label" msgid="2804351898001038951">"Жеке"</string>
- <string name="managed_profile_label" msgid="6260850669674791528">"Жұмыс"</string>
+ <string name="user_owner_label" msgid="1119010402169916617">"Жекеге ауысу"</string>
+ <string name="managed_profile_label" msgid="5289992269827577857">"Жұмысқа ауысу"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"Контактілер"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"контактілерге кіру"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"Орын"</string>
@@ -1045,7 +1045,8 @@
<string name="no_permissions" msgid="7283357728219338112">"Рұқсат қажет емес"</string>
<string name="perm_costs_money" msgid="4902470324142151116">"бұған төлем қажет болуы мүмкін"</string>
<string name="dlg_ok" msgid="7376953167039865701">"Жарайды"</string>
- <string name="usb_charging_notification_title" msgid="4004114449249406402">"Зарядтауға арналған USB"</string>
+ <string name="usb_charging_notification_title" msgid="6895185153353640787">"USB арқылы зарядтау"</string>
+ <string name="usb_supplying_notification_title" msgid="5310642257296510271">"USB жалғанған құрылғыға қуат беруде"</string>
<string name="usb_mtp_notification_title" msgid="8396264943589760855">"Файлды тасымалдауға арналған USB"</string>
<string name="usb_ptp_notification_title" msgid="1347328437083192112">"Фотосуретті тасымалдауға арналған USB"</string>
<string name="usb_midi_notification_title" msgid="4850904915889144654">"MIDI режиміне арналған USB"</string>
@@ -1060,11 +1061,10 @@
<string name="share_remote_bugreport_action" msgid="6249476773913384948">"БӨЛІСУ"</string>
<string name="decline_remote_bugreport_action" msgid="6230987241608770062">"ҚАБЫЛДАМАУ"</string>
<string name="select_input_method" msgid="8547250819326693584">"Пернетақтаны өзгерту"</string>
- <string name="configure_input_methods" msgid="5673193194563164021">"Басқа пернетақталар"</string>
<string name="show_ime" msgid="2506087537466597099">"Физикалық пернетақта белсенді кезде оны экранда ұстау"</string>
<string name="hardware" msgid="194658061510127999">"Виртуалды пернетақтаны көрсету"</string>
- <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Пернетақта орналасуын таңдау"</string>
- <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Пернетақта орналасуын таңдау үшін түртіңіз."</string>
+ <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Физикалық пернетақтаны конфигурациялау"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Тіл мен пернетақта схемасын таңдау үшін түртіңіз"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"үміткерлер"</u></string>
diff --git a/core/res/res/values-km-rKH/strings.xml b/core/res/res/values-km-rKH/strings.xml
index fdee3aa..30d3c0a 100644
--- a/core/res/res/values-km-rKH/strings.xml
+++ b/core/res/res/values-km-rKH/strings.xml
@@ -233,8 +233,8 @@
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"មាតិកាត្រូវបានលាក់ដោយផ្អែកលើគោលការណ៍"</string>
<string name="safeMode" msgid="2788228061547930246">"របៀបសុវត្ថិភាព"</string>
<string name="android_system_label" msgid="6577375335728551336">"ប្រព័ន្ធ Android"</string>
- <string name="user_owner_label" msgid="2804351898001038951">"ផ្ទាល់ខ្លួន"</string>
- <string name="managed_profile_label" msgid="6260850669674791528">"កន្លែងធ្វើការ"</string>
+ <string name="user_owner_label" msgid="1119010402169916617">"ប្តូរទៅផ្ទាល់ខ្លួន"</string>
+ <string name="managed_profile_label" msgid="5289992269827577857">"ប្តូរទៅការងារ"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"ទំនាក់ទំនង"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"ចូលប្រើទំនាក់ទំនងរបស់អ្នក"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"ទីតាំង"</string>
@@ -1047,7 +1047,8 @@
<string name="no_permissions" msgid="7283357728219338112">"មិនទាមទារសិទ្ធិ"</string>
<string name="perm_costs_money" msgid="4902470324142151116">"វាអាចកាត់លុយអ្នក"</string>
<string name="dlg_ok" msgid="7376953167039865701">"យល់ព្រម"</string>
- <string name="usb_charging_notification_title" msgid="4004114449249406402">"USB សម្រាប់បញ្ចូលថ្ម"</string>
+ <string name="usb_charging_notification_title" msgid="6895185153353640787">"USB កំពុងសាកឧបករណ៍នេះ"</string>
+ <string name="usb_supplying_notification_title" msgid="5310642257296510271">"USB កំពុងផ្គត់ផ្គង់ថាមពលទៅឧបករណ៍ដែលបានភ្ជាប់"</string>
<string name="usb_mtp_notification_title" msgid="8396264943589760855">"USB សម្រាប់ការផ្ទេរឯកសារ"</string>
<string name="usb_ptp_notification_title" msgid="1347328437083192112">"USB សម្រាប់ការផ្ទេររូបថត"</string>
<string name="usb_midi_notification_title" msgid="4850904915889144654">"USB សម្រាប់ MIDI"</string>
@@ -1062,11 +1063,10 @@
<string name="share_remote_bugreport_action" msgid="6249476773913384948">"ចែករំលែក"</string>
<string name="decline_remote_bugreport_action" msgid="6230987241608770062">"បដិសេធ"</string>
<string name="select_input_method" msgid="8547250819326693584">"ប្ដូរក្ដារចុច"</string>
- <string name="configure_input_methods" msgid="5673193194563164021">"ក្តារចុចផ្សេងទៀត"</string>
<string name="show_ime" msgid="2506087537466597099">"ទុកវានៅលើអេក្រង់ខណៈពេលក្តារចុចពិតប្រាកដកំពុងសកម្ម"</string>
<string name="hardware" msgid="194658061510127999">"បង្ហាញក្ដារចុចនិម្មិត"</string>
- <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"ជ្រើសប្លង់ក្ដារចុច"</string>
- <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"ប៉ះ ដើម្បីជ្រើសប្លង់ក្ដារចុច។"</string>
+ <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"កំណត់រចនាសម្ព័ន្ធក្តារចុចពិតប្រាកដ"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"ប៉ះដើម្បីជ្រើសភាសា និងប្លង់"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"បេក្ខជន"</u></string>
diff --git a/core/res/res/values-kn-rIN/strings.xml b/core/res/res/values-kn-rIN/strings.xml
index b31b2bb..087b399 100644
--- a/core/res/res/values-kn-rIN/strings.xml
+++ b/core/res/res/values-kn-rIN/strings.xml
@@ -233,8 +233,8 @@
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"ನೀತಿಯಿಂದ ಮರೆಮಾಡಲಾಗಿರುವ ವಿಷಯಗಳು"</string>
<string name="safeMode" msgid="2788228061547930246">"ಸುರಕ್ಷಿತ ಮೋಡ್"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android ಸಿಸ್ಟಂ"</string>
- <string name="user_owner_label" msgid="2804351898001038951">"ವೈಯಕ್ತಿಕ"</string>
- <string name="managed_profile_label" msgid="6260850669674791528">"ಕಚೇರಿ"</string>
+ <string name="user_owner_label" msgid="1119010402169916617">"ವೈಯಕ್ತಿಕಗೆ ಬದಲಿಸಿ"</string>
+ <string name="managed_profile_label" msgid="5289992269827577857">"ಕೆಲಸಕ್ಕೆ ಬದಲಿಸು"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"ಸಂಪರ್ಕಗಳು"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"ನಿಮ್ಮ ಸಂಪರ್ಕಗಳನ್ನು ಪ್ರವೇಶಿಸಲು"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"ಸ್ಥಳ"</string>
@@ -1045,7 +1045,8 @@
<string name="no_permissions" msgid="7283357728219338112">"ಯಾವುದೇ ಅನುಮತಿಗಳ ಅಗತ್ಯವಿಲ್ಲ"</string>
<string name="perm_costs_money" msgid="4902470324142151116">"ಇದು ನಿಮ್ಮ ಹಣವನ್ನು ವ್ಯಯಿಸಬಹುದು"</string>
<string name="dlg_ok" msgid="7376953167039865701">"ಸರಿ"</string>
- <string name="usb_charging_notification_title" msgid="4004114449249406402">"ಚಾರ್ಜ್ ಮಾಡುವುದಕ್ಕಾಗಿ USB"</string>
+ <string name="usb_charging_notification_title" msgid="6895185153353640787">"ಈ ಸಾಧನಕ್ಕೆ USB ಅನ್ನು ಚಾರ್ಜ್ ಮಾಡಲಾಗುತ್ತಿದೆ"</string>
+ <string name="usb_supplying_notification_title" msgid="5310642257296510271">"USB, ಲಗತ್ತಿಸಲಾದ ಸಾಧನಕ್ಕೆ ಪವರ್ ಪೂರೈಸುತ್ತಿದೆ"</string>
<string name="usb_mtp_notification_title" msgid="8396264943589760855">"ಫೈಲ್ ವರ್ಗಾವಣೆಗೆ USB"</string>
<string name="usb_ptp_notification_title" msgid="1347328437083192112">"ಫೋಟೋ ವರ್ಗಾವಣೆಗೆ USB"</string>
<string name="usb_midi_notification_title" msgid="4850904915889144654">"MIDI ಗೆ USB"</string>
@@ -1060,11 +1061,10 @@
<string name="share_remote_bugreport_action" msgid="6249476773913384948">"ಹಂಚಿಕೊಳ್ಳಿ"</string>
<string name="decline_remote_bugreport_action" msgid="6230987241608770062">"ನಿರಾಕರಿಸು"</string>
<string name="select_input_method" msgid="8547250819326693584">"ಕೀಬೋರ್ಡ್ ಬದಲಿಸಿ"</string>
- <string name="configure_input_methods" msgid="5673193194563164021">"ಇತರೆ ಕೀಬೋರ್ಡ್ಗಳು"</string>
<string name="show_ime" msgid="2506087537466597099">"ಭೌತಿಕ ಕೀಬೋರ್ಡ್ ಸಕ್ರಿಯವಾಗಿರುವಾಗ ಅದನ್ನು ಪರದೆಯ ಮೇಲೆ ಇರಿಸಿಕೊಳ್ಳಿ"</string>
<string name="hardware" msgid="194658061510127999">"ವರ್ಚ್ಯುಯಲ್ ಕೀಬೋರ್ಡ್ ತೋರಿಸು"</string>
- <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"ಕೀಬೋರ್ಡ್ ಲೇಔಟ್ ಆಯ್ಕೆಮಾಡಿ"</string>
- <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"ಕೀಬೋರ್ಡ್ ಲೇಔಟ್ ಆಯ್ಕೆ ಮಾಡಲು ಸ್ಪರ್ಶಿಸಿ"</string>
+ <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"ಭೌತಿಕ ಕೀಬೋರ್ಡ್ ಕಾನ್ಫಿಗರ್ ಮಾಡಿ"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"ಭಾಷೆ ಮತ್ತು ವಿನ್ಯಾಸವನ್ನು ಆಯ್ಕೆ ಮಾಡಲು ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"ಅಭ್ಯರ್ಥಿಗಳು"</u></string>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index 51418d9..52de5ba 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -233,8 +233,8 @@
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"콘텐츠가 정책에 의해 숨겨졌습니다."</string>
<string name="safeMode" msgid="2788228061547930246">"안전 모드"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android 시스템"</string>
- <string name="user_owner_label" msgid="2804351898001038951">"개인"</string>
- <string name="managed_profile_label" msgid="6260850669674791528">"직장"</string>
+ <string name="user_owner_label" msgid="1119010402169916617">"개인으로 전환"</string>
+ <string name="managed_profile_label" msgid="5289992269827577857">"직장으로 전환"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"주소록"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"주소록에 접근할 수 있도록"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"위치"</string>
@@ -1045,7 +1045,8 @@
<string name="no_permissions" msgid="7283357728219338112">"권한 필요 없음"</string>
<string name="perm_costs_money" msgid="4902470324142151116">"비용이 부과될 수 있습니다."</string>
<string name="dlg_ok" msgid="7376953167039865701">"확인"</string>
- <string name="usb_charging_notification_title" msgid="4004114449249406402">"충전용 USB"</string>
+ <string name="usb_charging_notification_title" msgid="6895185153353640787">"이 기기를 USB로 충전"</string>
+ <string name="usb_supplying_notification_title" msgid="5310642257296510271">"연결된 기기에 USB로 전력 공급"</string>
<string name="usb_mtp_notification_title" msgid="8396264943589760855">"파일 전송용 USB"</string>
<string name="usb_ptp_notification_title" msgid="1347328437083192112">"사진 전송용 USB"</string>
<string name="usb_midi_notification_title" msgid="4850904915889144654">"MIDI용 USB"</string>
@@ -1060,11 +1061,10 @@
<string name="share_remote_bugreport_action" msgid="6249476773913384948">"공유"</string>
<string name="decline_remote_bugreport_action" msgid="6230987241608770062">"거부"</string>
<string name="select_input_method" msgid="8547250819326693584">"키보드 변경"</string>
- <string name="configure_input_methods" msgid="5673193194563164021">"기타 키보드"</string>
<string name="show_ime" msgid="2506087537466597099">"물리적 키보드가 활성 상태인 경우 화면에 켜 둠"</string>
<string name="hardware" msgid="194658061510127999">"가상 키보드 표시"</string>
- <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"키보드 레이아웃 선택"</string>
- <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"터치하여 키보드 레이아웃을 선택합니다."</string>
+ <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"물리적 키보드 설정"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"탭하여 언어와 레이아웃을 선택하세요."</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"가능한 원인"</u></string>
diff --git a/core/res/res/values-ky-rKG/strings.xml b/core/res/res/values-ky-rKG/strings.xml
index 32f3d9a..34cc7e5 100644
--- a/core/res/res/values-ky-rKG/strings.xml
+++ b/core/res/res/values-ky-rKG/strings.xml
@@ -233,8 +233,8 @@
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Тийиштүү саясат боюнча жашырылган мазмундар"</string>
<string name="safeMode" msgid="2788228061547930246">"Коопсуз режим"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android Тутуму"</string>
- <string name="user_owner_label" msgid="2804351898001038951">"Жеке"</string>
- <string name="managed_profile_label" msgid="6260850669674791528">"Жумуш"</string>
+ <string name="user_owner_label" msgid="1119010402169916617">"Жеке профилге которулуу"</string>
+ <string name="managed_profile_label" msgid="5289992269827577857">"Жумуш профилине которулуу"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"Байланыштар"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"байланыштарыңызга уруксат"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"Жайгашкан жер"</string>
@@ -1046,7 +1046,8 @@
<string name="no_permissions" msgid="7283357728219338112">"Эч уруксаттын кереги жок"</string>
<string name="perm_costs_money" msgid="4902470324142151116">"бул үчүн акы алынышы мүмкүн"</string>
<string name="dlg_ok" msgid="7376953167039865701">"Жарайт"</string>
- <string name="usb_charging_notification_title" msgid="4004114449249406402">"Кубаттоо үчүн USB"</string>
+ <string name="usb_charging_notification_title" msgid="6895185153353640787">"Бул түзмөк USB менен кубатталууда"</string>
+ <string name="usb_supplying_notification_title" msgid="5310642257296510271">"Тиркелген түзмөк USB менен кубатталууда"</string>
<string name="usb_mtp_notification_title" msgid="8396264943589760855">"Файл өткөрүү үчүн USB"</string>
<string name="usb_ptp_notification_title" msgid="1347328437083192112">"Сүрөт өткөрүү үчүн USB"</string>
<string name="usb_midi_notification_title" msgid="4850904915889144654">"MIDI үчүн USB"</string>
@@ -1061,11 +1062,10 @@
<string name="share_remote_bugreport_action" msgid="6249476773913384948">"БӨЛҮШҮҮ"</string>
<string name="decline_remote_bugreport_action" msgid="6230987241608770062">"ЧЕТКЕ КАГУУ"</string>
<string name="select_input_method" msgid="8547250819326693584">"Баскычтопту өзгөртүү"</string>
- <string name="configure_input_methods" msgid="5673193194563164021">"Башка баскычтоптор"</string>
<string name="show_ime" msgid="2506087537466597099">"Баскычтоп иштетилгенде экранда көрүнүп турсун"</string>
<string name="hardware" msgid="194658061510127999">"Виртуалдык баскычтоп"</string>
- <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Тергичтин жайгашуусун тандоо"</string>
- <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Тергичтин жайгашуусун тандаш үчүн басыңыз."</string>
+ <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Аппараттык баскычтопту конфигурациялоо"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Тил жана калып тандоо үчүн таптап коюңуз"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"талапкерлер"</u></string>
@@ -1225,7 +1225,7 @@
<string name="action_menu_overflow_description" msgid="2295659037509008453">"Дагы параметрлер"</string>
<string name="action_bar_home_description_format" msgid="7965984360903693903">"%1$s, %2$s"</string>
<string name="action_bar_home_subtitle_description_format" msgid="6985546530471780727">"%1$s, %2$s, %3$s"</string>
- <string name="storage_internal" msgid="3570990907910199483">"Бөлүшүлгөн ички сактагыч"</string>
+ <string name="storage_internal" msgid="3570990907910199483">"Жалпы ички сактагыч"</string>
<string name="storage_sd_card" msgid="3282948861378286745">"SD-карта"</string>
<string name="storage_sd_card_label" msgid="6347111320774379257">"<xliff:g id="MANUFACTURER">%s</xliff:g> SD карта"</string>
<string name="storage_usb_drive" msgid="6261899683292244209">"USB түзмөк"</string>
diff --git a/core/res/res/values-lo-rLA/strings.xml b/core/res/res/values-lo-rLA/strings.xml
index 94fb2db..ea62f9b 100644
--- a/core/res/res/values-lo-rLA/strings.xml
+++ b/core/res/res/values-lo-rLA/strings.xml
@@ -233,8 +233,8 @@
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"ເນື້ອຫາຖືກເຊື່ອງຕາມນະໂຍບາຍ"</string>
<string name="safeMode" msgid="2788228061547930246">"Safe mode"</string>
<string name="android_system_label" msgid="6577375335728551336">"ລະບົບ Android"</string>
- <string name="user_owner_label" msgid="2804351898001038951">"ສ່ວນໂຕ"</string>
- <string name="managed_profile_label" msgid="6260850669674791528">"ບ່ອນເຮັດວຽກ"</string>
+ <string name="user_owner_label" msgid="1119010402169916617">"ສະລັບໄປໂປຣໄຟລ໌ສ່ວນຕົວ"</string>
+ <string name="managed_profile_label" msgid="5289992269827577857">"ສະລັບໄປໂປຣໄຟລ໌ວຽ."</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"ລາຍຊື່"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"ເຂົ້າຫາລາຍຊື່ຂອງທ່ານ"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"ສະຖານທີ່"</string>
@@ -1045,7 +1045,8 @@
<string name="no_permissions" msgid="7283357728219338112">"ບໍ່ຕ້ອງການການອະນຸຍາດ"</string>
<string name="perm_costs_money" msgid="4902470324142151116">"ລາຍການນີ້ອາດມີການເກັບເງິນ"</string>
<string name="dlg_ok" msgid="7376953167039865701">"ຕົກລົງ"</string>
- <string name="usb_charging_notification_title" msgid="4004114449249406402">"USB ສຳລັບການສາກ"</string>
+ <string name="usb_charging_notification_title" msgid="6895185153353640787">"ກຳລັງສາກໄຟ USB ອຸປະກອນນີ້"</string>
+ <string name="usb_supplying_notification_title" msgid="5310642257296510271">"USB ກຳລັງສະໜອງໄຟໃຫ້ກັບອຸປະກອນທີ່ເຊື່ອມຕໍ່ກັນ"</string>
<string name="usb_mtp_notification_title" msgid="8396264943589760855">"USB ສຳລັບການໂອນໄຟລ໌"</string>
<string name="usb_ptp_notification_title" msgid="1347328437083192112">"USB ສຳລັບການໂອນໄຟລ໌"</string>
<string name="usb_midi_notification_title" msgid="4850904915889144654">"USB ສຳລັບ MIDI"</string>
@@ -1060,11 +1061,10 @@
<string name="share_remote_bugreport_action" msgid="6249476773913384948">"ແບ່ງປັນ"</string>
<string name="decline_remote_bugreport_action" msgid="6230987241608770062">"ປະຕິເສດ"</string>
<string name="select_input_method" msgid="8547250819326693584">"ປ່ຽນແປ້ນພິມ"</string>
- <string name="configure_input_methods" msgid="5673193194563164021">"ແປ້ນພິມອື່ນໆ"</string>
<string name="show_ime" msgid="2506087537466597099">"ເປີດໃຊ້ໃຫ້ມັນຢູ່ໃນໜ້າຈໍໃນຂະນະທີ່ໃຊ້ແປ້ນພິມພາຍນອກຢູ່"</string>
<string name="hardware" msgid="194658061510127999">"ສະແດງແປ້ນພິມສະເໝືອນ"</string>
- <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"ເລືອກຮູບແບບແປ້ນພິມ"</string>
- <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"ກົດເພື່ອເລືອກຮູບແບບແປ້ນພິມ."</string>
+ <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"ຕັ້ງຄ່າແປ້ນພິມພາຍນອກ"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"ແຕະເພື່ອເລືອກພາສາ ແລະ ໂຄງແປ້ນພິມ"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"ຕົວເລືອກ"</u></string>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index c4c4fa2..3e815ec 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -237,8 +237,8 @@
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Turinys paslėptas vadovaujantis politika"</string>
<string name="safeMode" msgid="2788228061547930246">"Saugos režimas"</string>
<string name="android_system_label" msgid="6577375335728551336">"„Android“ sistema"</string>
- <string name="user_owner_label" msgid="2804351898001038951">"Asmeninė"</string>
- <string name="managed_profile_label" msgid="6260850669674791528">"Darbo"</string>
+ <string name="user_owner_label" msgid="1119010402169916617">"Perjungti į asmeninį režimą"</string>
+ <string name="managed_profile_label" msgid="5289992269827577857">"Perjungti į darbo režimą"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"Kontaktai"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"pasiekti kontaktus"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"Vietovė"</string>
@@ -1061,7 +1061,8 @@
<string name="no_permissions" msgid="7283357728219338112">"Nereikia leidimų"</string>
<string name="perm_costs_money" msgid="4902470324142151116">"tai gali kainuoti"</string>
<string name="dlg_ok" msgid="7376953167039865701">"Gerai"</string>
- <string name="usb_charging_notification_title" msgid="4004114449249406402">"USB (įkrovimas)"</string>
+ <string name="usb_charging_notification_title" msgid="6895185153353640787">"Įrenginys įkraunamas naudojant USB"</string>
+ <string name="usb_supplying_notification_title" msgid="5310642257296510271">"Maitinimas prijungtam įrenginiui tiekiamas naudojant USB"</string>
<string name="usb_mtp_notification_title" msgid="8396264943589760855">"USB (failų perkėlimas)"</string>
<string name="usb_ptp_notification_title" msgid="1347328437083192112">"USB (nuotraukų perkėlimas)"</string>
<string name="usb_midi_notification_title" msgid="4850904915889144654">"USB (MIDI)"</string>
@@ -1076,11 +1077,10 @@
<string name="share_remote_bugreport_action" msgid="6249476773913384948">"BENDRINTI"</string>
<string name="decline_remote_bugreport_action" msgid="6230987241608770062">"ATMESTI"</string>
<string name="select_input_method" msgid="8547250819326693584">"Klaviatūros keitimas"</string>
- <string name="configure_input_methods" msgid="5673193194563164021">"Kitos klaviatūros"</string>
<string name="show_ime" msgid="2506087537466597099">"Palikti ekrane, kol fizinė klaviatūra aktyvi"</string>
<string name="hardware" msgid="194658061510127999">"Rodyti virtualiąją klaviatūrą"</string>
- <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Pasirinkite klaviatūros išdėstymą"</string>
- <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Palieskite, kad pasirinktumėte klaviatūros išdėstymą."</string>
+ <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Fizinės klaviatūros konfigūravimas"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Palieskite, kad pasirinktumėte kalbą ir išdėstymą"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" AĄBCČDEĘĖFGHIĮYJKLMNOPRSŠTUŲŪVZŽ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789AĄBCČDEĘĖFGHIĮYJKLMNOPRSŠTUŲŪVZŽ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"kandidatai"</u></string>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index 566180f..56001fc 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -235,8 +235,8 @@
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Saskaņā ar politiku saturs ir paslēpts."</string>
<string name="safeMode" msgid="2788228061547930246">"Drošais režīms"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android sistēma"</string>
- <string name="user_owner_label" msgid="2804351898001038951">"Personisks"</string>
- <string name="managed_profile_label" msgid="6260850669674791528">"Darba"</string>
+ <string name="user_owner_label" msgid="1119010402169916617">"Pārslēgt personīgo profilu"</string>
+ <string name="managed_profile_label" msgid="5289992269827577857">"Pārslēgt darba profilu"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"Kontaktpersonas"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"piekļūt jūsu kontaktpersonu datiem"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"Atrašanās vieta"</string>
@@ -1053,7 +1053,8 @@
<string name="no_permissions" msgid="7283357728219338112">"Atļaujas nav nepieciešamas."</string>
<string name="perm_costs_money" msgid="4902470324142151116">"par to no jums var tikt iekasēta maksa"</string>
<string name="dlg_ok" msgid="7376953167039865701">"Labi"</string>
- <string name="usb_charging_notification_title" msgid="4004114449249406402">"USB savienojums uzlādei"</string>
+ <string name="usb_charging_notification_title" msgid="6895185153353640787">"USB savienojums tiek izmantots šīs ierīces uzlādei"</string>
+ <string name="usb_supplying_notification_title" msgid="5310642257296510271">"USB savienojums tiek izmantots pievienotās ierīces barošanai"</string>
<string name="usb_mtp_notification_title" msgid="8396264943589760855">"USB savienojums failu pārsūtīšanai"</string>
<string name="usb_ptp_notification_title" msgid="1347328437083192112">"USB savienojums fotoattēlu pārsūtīšanai"</string>
<string name="usb_midi_notification_title" msgid="4850904915889144654">"USB savienojums MIDI režīmā"</string>
@@ -1068,11 +1069,10 @@
<string name="share_remote_bugreport_action" msgid="6249476773913384948">"KOPĪGOT"</string>
<string name="decline_remote_bugreport_action" msgid="6230987241608770062">"NORAIDĪT"</string>
<string name="select_input_method" msgid="8547250819326693584">"Tastatūras maiņa"</string>
- <string name="configure_input_methods" msgid="5673193194563164021">"Citas tastatūras"</string>
<string name="show_ime" msgid="2506087537466597099">"Paturēt ekrānā, kamēr ir aktīva fiziskā tastatūra"</string>
<string name="hardware" msgid="194658061510127999">"Virtuālās tastatūras rādīšana"</string>
- <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Atlasiet tastatūras izkārtojumu"</string>
- <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Pieskarieties, lai atlasītu tastatūras izkārtojumu."</string>
+ <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Fiziskās tastatūras konfigurēšana"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Pieskarieties, lai atlasītu valodu un izkārtojumu"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" AĀBCČDEĒFGĢHIĪJKĶLĻMNŅOPRSŠTUŪVZŽ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789AĀBCČDEĒFGĢHIĪJKĶLĻMNŅOPRSŠTUŪVZŽ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"kandidāti"</u></string>
diff --git a/core/res/res/values-mk-rMK/strings.xml b/core/res/res/values-mk-rMK/strings.xml
index d9dae7a..060a9fa 100644
--- a/core/res/res/values-mk-rMK/strings.xml
+++ b/core/res/res/values-mk-rMK/strings.xml
@@ -233,8 +233,8 @@
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Содржините се скриени поради политиката"</string>
<string name="safeMode" msgid="2788228061547930246">"Безбеден режим"</string>
<string name="android_system_label" msgid="6577375335728551336">"Систем Android"</string>
- <string name="user_owner_label" msgid="2804351898001038951">"Лични"</string>
- <string name="managed_profile_label" msgid="6260850669674791528">"Работа"</string>
+ <string name="user_owner_label" msgid="1119010402169916617">"Префрлете на личен профил"</string>
+ <string name="managed_profile_label" msgid="5289992269827577857">"Префрли на работен профил"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"Контакти"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"пристапува до контактите"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"Локација"</string>
@@ -1045,7 +1045,8 @@
<string name="no_permissions" msgid="7283357728219338112">"Не се потребни дозволи"</string>
<string name="perm_costs_money" msgid="4902470324142151116">"ова може да ве чини пари"</string>
<string name="dlg_ok" msgid="7376953167039865701">"Во ред"</string>
- <string name="usb_charging_notification_title" msgid="4004114449249406402">"УСБ за полнење"</string>
+ <string name="usb_charging_notification_title" msgid="6895185153353640787">"Уредов се полни преку USB"</string>
+ <string name="usb_supplying_notification_title" msgid="5310642257296510271">"Прикачениот уред се напојува преку USB"</string>
<string name="usb_mtp_notification_title" msgid="8396264943589760855">"УСБ за пренос на датотеки"</string>
<string name="usb_ptp_notification_title" msgid="1347328437083192112">"УСБ за пренос на фотографии"</string>
<string name="usb_midi_notification_title" msgid="4850904915889144654">"УСБ за МИДИ"</string>
@@ -1060,11 +1061,10 @@
<string name="share_remote_bugreport_action" msgid="6249476773913384948">"СПОДЕЛИ"</string>
<string name="decline_remote_bugreport_action" msgid="6230987241608770062">"ОДБИЈ"</string>
<string name="select_input_method" msgid="8547250819326693584">"Измени тастатура"</string>
- <string name="configure_input_methods" msgid="5673193194563164021">"Други тастатури"</string>
<string name="show_ime" msgid="2506087537466597099">"Прикажувај го на екранот додека е активна физичката тастатура"</string>
<string name="hardware" msgid="194658061510127999">"Прикажи виртуелна тастатура"</string>
- <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Избери изглед на тастатура"</string>
- <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Допри за да избереш изглед на тастатура."</string>
+ <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Конфигурирајте физичка тастатура"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Допрете за избирање јазик и распоред"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"кандидати"</u></string>
diff --git a/core/res/res/values-ml-rIN/strings.xml b/core/res/res/values-ml-rIN/strings.xml
index 16ededc..f6ff1d8 100644
--- a/core/res/res/values-ml-rIN/strings.xml
+++ b/core/res/res/values-ml-rIN/strings.xml
@@ -233,8 +233,8 @@
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"നയം അനുസരിച്ച് ഉള്ളടക്കം മറച്ചിരിക്കുന്നു"</string>
<string name="safeMode" msgid="2788228061547930246">"സുരക്ഷിത മോഡ്"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android സിസ്റ്റം"</string>
- <string name="user_owner_label" msgid="2804351898001038951">"വ്യക്തിഗതം"</string>
- <string name="managed_profile_label" msgid="6260850669674791528">"ഔദ്യോഗിക പ്രൊഫൈൽ"</string>
+ <string name="user_owner_label" msgid="1119010402169916617">"വ്യക്തിഗത പ്രൊഫൈലിലേക്ക് മാറുക"</string>
+ <string name="managed_profile_label" msgid="5289992269827577857">"ഔദ്യോഗിക പ്രൊഫൈലിലേക്ക് മാറുക"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"കോൺടാക്റ്റുകൾ"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"നിങ്ങളുടെ കോൺടാക്റ്റുകൾ ആക്സസ്സ് ചെയ്യുക"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"ലൊക്കേഷൻ"</string>
@@ -1045,7 +1045,8 @@
<string name="no_permissions" msgid="7283357728219338112">"അനുമതികളൊന്നും ആവശ്യമില്ല"</string>
<string name="perm_costs_money" msgid="4902470324142151116">"ഇത് നിങ്ങൾക്ക് പണച്ചെലവിനിടയാക്കാം"</string>
<string name="dlg_ok" msgid="7376953167039865701">"ശരി"</string>
- <string name="usb_charging_notification_title" msgid="4004114449249406402">"ചാർജ്ജിംഗിനായുള്ള USB"</string>
+ <string name="usb_charging_notification_title" msgid="6895185153353640787">"ഈ ഉപകരണം USB ചാർജുചെയ്യുന്നു"</string>
+ <string name="usb_supplying_notification_title" msgid="5310642257296510271">"ഘടിപ്പിച്ചിട്ടുള്ള ഉപകരണത്തിന് USB വൈദ്യുതി നൽകുന്നു"</string>
<string name="usb_mtp_notification_title" msgid="8396264943589760855">"ഫയൽ കൈമാറ്റത്തിനുള്ള USB"</string>
<string name="usb_ptp_notification_title" msgid="1347328437083192112">"ഫോട്ടോ കൈമാറ്റത്തിനായുള്ള USB"</string>
<string name="usb_midi_notification_title" msgid="4850904915889144654">"MIDI-യ്ക്കായുള്ള USB"</string>
@@ -1060,11 +1061,10 @@
<string name="share_remote_bugreport_action" msgid="6249476773913384948">"പങ്കിടുക"</string>
<string name="decline_remote_bugreport_action" msgid="6230987241608770062">"നിരസിക്കുക"</string>
<string name="select_input_method" msgid="8547250819326693584">"കീബോഡ് മാറ്റുക"</string>
- <string name="configure_input_methods" msgid="5673193194563164021">"മറ്റ് കീബോർഡുകൾ"</string>
<string name="show_ime" msgid="2506087537466597099">"ഫിസിക്കൽ കീബോർഡ് സജീവമായിരിക്കുമ്പോൾ സ്ക്രീനിൽ നിലനിർത്തുക"</string>
<string name="hardware" msgid="194658061510127999">"വെർച്വൽ കീബോർഡ് കാണിക്കുക"</string>
- <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"കീബോർഡ് ലേഔട്ട് തിരഞ്ഞെടുക്കുക"</string>
- <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"ഒരു കീബോർഡ് ലേഔട്ട് തിരഞ്ഞെടുക്കാൻ സ്പർശിക്കുക."</string>
+ <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"ഫിസിക്കൽ കീബോർഡ് കോൺഫിഗർ ചെയ്യുക"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"ഭാഷയും ലേഔട്ടും തിരഞ്ഞെടുക്കുന്നതിന് ടാപ്പുചെയ്യുക"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"കാൻഡിഡേറ്റുകൾ"</u></string>
diff --git a/core/res/res/values-mn-rMN/strings.xml b/core/res/res/values-mn-rMN/strings.xml
index 0f31862..75105e6 100644
--- a/core/res/res/values-mn-rMN/strings.xml
+++ b/core/res/res/values-mn-rMN/strings.xml
@@ -233,8 +233,8 @@
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Удирдамжийн дагуу нуусан агуулга"</string>
<string name="safeMode" msgid="2788228061547930246">"Аюулгүй горим"</string>
<string name="android_system_label" msgid="6577375335728551336">"Андройд систем"</string>
- <string name="user_owner_label" msgid="2804351898001038951">"Хувийн"</string>
- <string name="managed_profile_label" msgid="6260850669674791528">"Ажил"</string>
+ <string name="user_owner_label" msgid="1119010402169916617">"\"Хувийн\" руу шилжих"</string>
+ <string name="managed_profile_label" msgid="5289992269827577857">"\"Ажлын\" руу шилжих"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"Харилцагчдын хаяг"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"харилцагч руугаа хандах"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"Байршил"</string>
@@ -1045,7 +1045,8 @@
<string name="no_permissions" msgid="7283357728219338112">"Зөвшөөрөл шаардахгүй"</string>
<string name="perm_costs_money" msgid="4902470324142151116">"Энэ таныг төлбөрт оруулж болзошгүй"</string>
<string name="dlg_ok" msgid="7376953167039865701">"Тийм"</string>
- <string name="usb_charging_notification_title" msgid="4004114449249406402">"USB цэнэглэгч"</string>
+ <string name="usb_charging_notification_title" msgid="6895185153353640787">"Энэ төхөөрөмжийг USB цэнэглэж байна"</string>
+ <string name="usb_supplying_notification_title" msgid="5310642257296510271">"Залгасан төхөөрөмжөөс USB цэнэг авч байна"</string>
<string name="usb_mtp_notification_title" msgid="8396264943589760855">"Файл шилжүүлэх USB"</string>
<string name="usb_ptp_notification_title" msgid="1347328437083192112">"Фото зураг шилжүүлэх USB"</string>
<string name="usb_midi_notification_title" msgid="4850904915889144654">"MIDI-ийн USB"</string>
@@ -1060,11 +1061,10 @@
<string name="share_remote_bugreport_action" msgid="6249476773913384948">"ХУВААЛЦАХ"</string>
<string name="decline_remote_bugreport_action" msgid="6230987241608770062">"ТАТГАЛЗАХ"</string>
<string name="select_input_method" msgid="8547250819326693584">"Гарыг өөрчлөх"</string>
- <string name="configure_input_methods" msgid="5673193194563164021">"Бусад гар"</string>
<string name="show_ime" msgid="2506087537466597099">"Бодит гар идэвхтэй үед үүнийг дэлгэцэнд харуулна уу"</string>
<string name="hardware" msgid="194658061510127999">"Хийсвэр гарыг харуулах"</string>
- <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Гарын схемийг сонгох"</string>
- <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Гарын схемийг сонгох бол хүрнэ үү."</string>
+ <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Биет гарыг хэлбэрт оруулах"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Хэл болон бүдүүвчийг сонгохын тулд дарна уу"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"нэр дэвшигч"</u></string>
diff --git a/core/res/res/values-mr-rIN/strings.xml b/core/res/res/values-mr-rIN/strings.xml
index 9a35efd..8a3e564 100644
--- a/core/res/res/values-mr-rIN/strings.xml
+++ b/core/res/res/values-mr-rIN/strings.xml
@@ -233,8 +233,8 @@
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"धोरणाद्वारे सामग्री लपविली"</string>
<string name="safeMode" msgid="2788228061547930246">"सुरक्षित मोड"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android सिस्टम"</string>
- <string name="user_owner_label" msgid="2804351898001038951">"वैयक्तिक"</string>
- <string name="managed_profile_label" msgid="6260850669674791528">"कार्य"</string>
+ <string name="user_owner_label" msgid="1119010402169916617">"वैयक्तिकवर स्विच करा"</string>
+ <string name="managed_profile_label" msgid="5289992269827577857">"कार्यावर स्विच करा"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"संपर्क"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"आपल्या संपर्कांवर प्रवेश"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"स्थान"</string>
@@ -1045,7 +1045,8 @@
<string name="no_permissions" msgid="7283357728219338112">"परवानग्या आवश्यक नाहीत"</string>
<string name="perm_costs_money" msgid="4902470324142151116">"यासाठी आपले पैसे खर्च होऊ शकतात"</string>
<string name="dlg_ok" msgid="7376953167039865701">"ठीक"</string>
- <string name="usb_charging_notification_title" msgid="4004114449249406402">"चार्जिंगसाठी USB"</string>
+ <string name="usb_charging_notification_title" msgid="6895185153353640787">"USB हे डिव्हाइस चार्ज करीत आहे"</string>
+ <string name="usb_supplying_notification_title" msgid="5310642257296510271">"USB संलग्न केलेल्या डिव्हाइसला पॉवरचा पुरवठा करीत आहे"</string>
<string name="usb_mtp_notification_title" msgid="8396264943589760855">"स्थानांतरणासाठी USB"</string>
<string name="usb_ptp_notification_title" msgid="1347328437083192112">"फोटो स्थानांतरणासाठी USB"</string>
<string name="usb_midi_notification_title" msgid="4850904915889144654">"MIDI साठी USB"</string>
@@ -1060,11 +1061,10 @@
<string name="share_remote_bugreport_action" msgid="6249476773913384948">"सामायिक करा"</string>
<string name="decline_remote_bugreport_action" msgid="6230987241608770062">"नकार द्या"</string>
<string name="select_input_method" msgid="8547250819326693584">"कीबोर्ड बदला"</string>
- <string name="configure_input_methods" msgid="5673193194563164021">"इतर कीबोर्ड"</string>
<string name="show_ime" msgid="2506087537466597099">"भौतिक कीबोर्ड सक्रिय असताना त्यास स्क्रीनवर ठेवा"</string>
<string name="hardware" msgid="194658061510127999">"व्हर्च्युअल कीबोर्ड दर्शवा"</string>
- <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"कीबोर्ड लेआउट निवडा"</string>
- <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"कीबोर्ड लेआउट निवडण्यासाठी स्पर्श करा."</string>
+ <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"वास्तविक कीबोर्ड कॉन्फिगर करा"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"भाषा आणि लेआउट निवडण्यासाठी टॅप करा"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"उमेदवार"</u></string>
diff --git a/core/res/res/values-ms-rMY/strings.xml b/core/res/res/values-ms-rMY/strings.xml
index 7c8ce0f..5db9c77 100644
--- a/core/res/res/values-ms-rMY/strings.xml
+++ b/core/res/res/values-ms-rMY/strings.xml
@@ -233,8 +233,8 @@
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Kandungan disembunyikan oleh dasar"</string>
<string name="safeMode" msgid="2788228061547930246">"Mod selamat"</string>
<string name="android_system_label" msgid="6577375335728551336">"Sistem Android"</string>
- <string name="user_owner_label" msgid="2804351898001038951">"Peribadi"</string>
- <string name="managed_profile_label" msgid="6260850669674791528">"Tempat Kerja"</string>
+ <string name="user_owner_label" msgid="1119010402169916617">"Beralih kepada Peribadi"</string>
+ <string name="managed_profile_label" msgid="5289992269827577857">"Beralih kepada Kerja"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"Kenalan"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"mengakses kenalan anda"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"Lokasi"</string>
@@ -1045,7 +1045,8 @@
<string name="no_permissions" msgid="7283357728219338112">"Tiada kebenaran diperlukan"</string>
<string name="perm_costs_money" msgid="4902470324142151116">"anda mungkin dikenakan bayaran"</string>
<string name="dlg_ok" msgid="7376953167039865701">"OK"</string>
- <string name="usb_charging_notification_title" msgid="4004114449249406402">"USB untuk pengecasan"</string>
+ <string name="usb_charging_notification_title" msgid="6895185153353640787">"Mengecas peranti ini melalui USB"</string>
+ <string name="usb_supplying_notification_title" msgid="5310642257296510271">"Membekalkan kuasa kepada peranti tersambung melalui USB"</string>
<string name="usb_mtp_notification_title" msgid="8396264943589760855">"USB untuk pemindahan fail"</string>
<string name="usb_ptp_notification_title" msgid="1347328437083192112">"USB untuk pemindahan foto"</string>
<string name="usb_midi_notification_title" msgid="4850904915889144654">"USB untuk MIDI"</string>
@@ -1060,11 +1061,10 @@
<string name="share_remote_bugreport_action" msgid="6249476773913384948">"KONGSI"</string>
<string name="decline_remote_bugreport_action" msgid="6230987241608770062">"TOLAK"</string>
<string name="select_input_method" msgid="8547250819326693584">"Tukar papan kekunci"</string>
- <string name="configure_input_methods" msgid="5673193194563164021">"Papan kekunci lain"</string>
<string name="show_ime" msgid="2506087537466597099">"Pastikannya pada skrin, semasa papan kekunci fizikal aktif"</string>
<string name="hardware" msgid="194658061510127999">"Tunjukkan papan kekunci maya"</string>
- <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Pilih susun atur papan kekunci"</string>
- <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Sentuh untuk memilih susun atur papan kekunci."</string>
+ <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Konfigurasikan papan kekunci fizikal"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Ketik untuk memilih bahasa dan susun atur"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"calon"</u></string>
diff --git a/core/res/res/values-my-rMM/strings.xml b/core/res/res/values-my-rMM/strings.xml
index 0c55986..5e5ec4e 100644
--- a/core/res/res/values-my-rMM/strings.xml
+++ b/core/res/res/values-my-rMM/strings.xml
@@ -233,8 +233,8 @@
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"မူဝါဒမှ အကြောင်းအရာများကို ဝှက်ထားသည်"</string>
<string name="safeMode" msgid="2788228061547930246">"အန္တရာယ်ကင်းမှု စနစ်(Safe mode)"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android စနစ်"</string>
- <string name="user_owner_label" msgid="2804351898001038951">"ကိုယ်ရေး"</string>
- <string name="managed_profile_label" msgid="6260850669674791528">"အလုပ်"</string>
+ <string name="user_owner_label" msgid="1119010402169916617">"ကိုယ်ပိုင်သီးသန့်အဖြစ် ပြောင်းပါ"</string>
+ <string name="managed_profile_label" msgid="5289992269827577857">"အလုပ်သို့ ပြောင်းပါ"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"အဆက်အသွယ်များ"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"သင့် အဆက်အသွယ်များအား ဝင်ရောက်သုံးရန်"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"တည်နေရာ"</string>
@@ -1045,7 +1045,8 @@
<string name="no_permissions" msgid="7283357728219338112">"ခွင့်ပြုချက်မလိုအပ်ပါ"</string>
<string name="perm_costs_money" msgid="4902470324142151116">"သင့်အတွက် ပိုက်ဆံကုန်ကျနိုင်ပါသည်"</string>
<string name="dlg_ok" msgid="7376953167039865701">"ကောင်းပြီ"</string>
- <string name="usb_charging_notification_title" msgid="4004114449249406402">"အားသွင်းရန်အတွက် USB"</string>
+ <string name="usb_charging_notification_title" msgid="6895185153353640787">"USB ဖြင့်ဤစက်ပစ္စည်းကို အားသွင်းနေသည်"</string>
+ <string name="usb_supplying_notification_title" msgid="5310642257296510271">"ချိတ်ဆက်ထားသည့် စက်ပစ္စည်းကို USB မှတစ်ဆင့် အားသွင်းနေသည်"</string>
<string name="usb_mtp_notification_title" msgid="8396264943589760855">"ဖိုင်လွှဲပြောင်းရန်အတွက် USB"</string>
<string name="usb_ptp_notification_title" msgid="1347328437083192112">"ဓာတ်ပုံလွှဲပြောင်းရန်အတွက် USB"</string>
<string name="usb_midi_notification_title" msgid="4850904915889144654">"MIDI အတွက် USB"</string>
@@ -1060,11 +1061,10 @@
<string name="share_remote_bugreport_action" msgid="6249476773913384948">"မျှဝေပါ"</string>
<string name="decline_remote_bugreport_action" msgid="6230987241608770062">"ငြင်းပယ်ပါ"</string>
<string name="select_input_method" msgid="8547250819326693584">"ကီးဘုတ် ပြောင်းလဲရန်"</string>
- <string name="configure_input_methods" msgid="5673193194563164021">"အခြားကီးဘုတ်များ"</string>
<string name="show_ime" msgid="2506087537466597099">"စက်၏ကီးဘုတ်ကိုအသုံးပြုနေစဉ် ၎င်းကိုမျက်နှာပြင်ပေါ်တွင် ထားပါ"</string>
<string name="hardware" msgid="194658061510127999">"ကီးဘုတ်အတုပြရန်"</string>
- <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"လက်ကွက် အပြင်အဆင်ရွေးရန်"</string>
- <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"လက်ကွက် အပြင်အဆင်ရွေးရန် တို့ထိပါ"</string>
+ <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"ရုပ်ပိုင်းဆိုင်ရာ အသွင်အပြင်ကို ပြင်ဆင်သတ်မှတ်ပါ"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"ဘာသာစကားနှင့် အသွင်အပြင်ရွေးချယ်ရန် တို့ပါ"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"ရွေးချယ်ခံမည့်သူ"</u></string>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index 7817321..cfccdeb 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -233,8 +233,8 @@
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Innholdet er skjult i henhold til retningslinjene"</string>
<string name="safeMode" msgid="2788228061547930246">"Sikkermodus"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android-system"</string>
- <string name="user_owner_label" msgid="2804351898001038951">"Personlig"</string>
- <string name="managed_profile_label" msgid="6260850669674791528">"Jobb"</string>
+ <string name="user_owner_label" msgid="1119010402169916617">"Bytt til den personlige profilen"</string>
+ <string name="managed_profile_label" msgid="5289992269827577857">"Bytt til jobbprofilen"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"Kontakter"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"se kontaktene dine"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"Posisjon"</string>
@@ -1045,7 +1045,8 @@
<string name="no_permissions" msgid="7283357728219338112">"Trenger ingen rettigheter"</string>
<string name="perm_costs_money" msgid="4902470324142151116">"dette kan koste deg penger"</string>
<string name="dlg_ok" msgid="7376953167039865701">"OK"</string>
- <string name="usb_charging_notification_title" msgid="4004114449249406402">"USB for lading"</string>
+ <string name="usb_charging_notification_title" msgid="6895185153353640787">"Enheten lades via USB"</string>
+ <string name="usb_supplying_notification_title" msgid="5310642257296510271">"Den tilkoblede enheten får strøm via USB"</string>
<string name="usb_mtp_notification_title" msgid="8396264943589760855">"USB for filoverføring"</string>
<string name="usb_ptp_notification_title" msgid="1347328437083192112">"USB for bildeoverføring"</string>
<string name="usb_midi_notification_title" msgid="4850904915889144654">"USB for MIDI"</string>
@@ -1060,11 +1061,10 @@
<string name="share_remote_bugreport_action" msgid="6249476773913384948">"DEL"</string>
<string name="decline_remote_bugreport_action" msgid="6230987241608770062">"AVSLÅ"</string>
<string name="select_input_method" msgid="8547250819326693584">"Endre tastatur"</string>
- <string name="configure_input_methods" msgid="5673193194563164021">"Andre tastaturoppsett"</string>
<string name="show_ime" msgid="2506087537466597099">"Ha den på skjermen mens det fysiske tastaturet er aktivt"</string>
<string name="hardware" msgid="194658061510127999">"Vis det virtuelle tastaturet"</string>
- <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Velg tastaturoppsett"</string>
- <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Trykk for å velge et tastaturoppsett"</string>
+ <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Konfigurer et fysisk tastatur"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Trykk for å velge språk og layout"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZÆØÅ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZÆØÅ"</string>
<string name="candidates_style" msgid="4333913089637062257">"TAG_FONT"<u>"kandidater"</u>"CLOSE_FONT"</string>
diff --git a/core/res/res/values-ne-rNP/strings.xml b/core/res/res/values-ne-rNP/strings.xml
index b6f3c37..fb817b5 100644
--- a/core/res/res/values-ne-rNP/strings.xml
+++ b/core/res/res/values-ne-rNP/strings.xml
@@ -233,8 +233,8 @@
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"नीतिद्वारा लुकाइएका सामग्री"</string>
<string name="safeMode" msgid="2788228061547930246">"सुरक्षित मोड"</string>
<string name="android_system_label" msgid="6577375335728551336">"एन्ड्रोइड प्रणाली"</string>
- <string name="user_owner_label" msgid="2804351898001038951">"व्यक्तिगत"</string>
- <string name="managed_profile_label" msgid="6260850669674791528">"काम"</string>
+ <string name="user_owner_label" msgid="1119010402169916617">"व्यक्तिगत प्रोफाइलमा स्विच गर्नुहोस्"</string>
+ <string name="managed_profile_label" msgid="5289992269827577857">"कार्य प्रोफाइलमा स्विच गर्नुहोस्"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"सम्पर्कहरू"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"तपाईँको सम्पर्कमा पहुँच गर्नुहोस्"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"स्थान"</string>
@@ -1051,7 +1051,8 @@
<string name="no_permissions" msgid="7283357728219338112">"कुनै अनुमति आवश्यक छैन"</string>
<string name="perm_costs_money" msgid="4902470324142151116">"सायद तपाईँलाई पैसा पर्न सक्छ।"</string>
<string name="dlg_ok" msgid="7376953167039865701">"ठिक छ"</string>
- <string name="usb_charging_notification_title" msgid="4004114449249406402">"चार्जका लागि USB"</string>
+ <string name="usb_charging_notification_title" msgid="6895185153353640787">"यस यन्त्रलाई USB मार्फत चार्ज गर्दै"</string>
+ <string name="usb_supplying_notification_title" msgid="5310642257296510271">"संलग्न गरिएको यन्त्रमा USB मार्फत पावर आपूर्ति गरिँदै"</string>
<string name="usb_mtp_notification_title" msgid="8396264943589760855">"फाइल स्थानान्तरणको लागि USB"</string>
<string name="usb_ptp_notification_title" msgid="1347328437083192112">"तस्बिर स्थानान्तरणको लागि USB"</string>
<string name="usb_midi_notification_title" msgid="4850904915889144654">"MIDI को लागि USB"</string>
@@ -1066,11 +1067,10 @@
<string name="share_remote_bugreport_action" msgid="6249476773913384948">"साझेदारी गर्नुहोस्"</string>
<string name="decline_remote_bugreport_action" msgid="6230987241608770062">"अस्वीकार गर्नुहोस्"</string>
<string name="select_input_method" msgid="8547250819326693584">"कुञ्जीपाटी परिवर्तन गर्नुहोस्"</string>
- <string name="configure_input_methods" msgid="5673193194563164021">"अन्य किबोर्डहरू"</string>
<string name="show_ime" msgid="2506087537466597099">"भौतिक किबोर्ड सक्रिय हुँदा यसलाई स्क्रिनमा राख्नुहोस्"</string>
<string name="hardware" msgid="194658061510127999">"भर्चुअल किबोर्ड देखाउनुहोस्"</string>
- <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"किबोर्ड रूपरेखा चयन गर्नुहोस्"</string>
- <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"किबोर्ड रूपरेखा चयन गर्न टच गर्नुहोस्।"</string>
+ <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"फिजिकल किबोर्डलाई कन्फिगर गर्नुहोस्"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"भाषा र लेआउट चयन गर्न ट्याप गर्नुहोस्"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"उम्मेदवार"</u></string>
diff --git a/core/res/res/values-night/themes_material_daynight.xml b/core/res/res/values-night/themes_material_daynight.xml
deleted file mode 100644
index b344582..0000000
--- a/core/res/res/values-night/themes_material_daynight.xml
+++ /dev/null
@@ -1,117 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2015 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-
-<!--
-===============================================================
- PLEASE READ
-===============================================================
-
-The Material themes must not be modified in order to pass CTS.
-Many related themes and styles depend on other values defined in this file.
-If you would like to provide custom themes and styles for your device,
-please see themes_device_defaults.xml.
-
-===============================================================
- PLEASE READ
-===============================================================
- -->
-<resources>
-
- <!-- Material theme (day/night version) for activities. -->
- <style name="Theme.Material.DayNight" parent="Theme.Material" />
-
- <!-- Variant of Material.DayNight that has a solid (opaque) action bar
- with an inverse color profile. The dark action bar sharply stands out against
- the light content (when applicable). -->
- <style name="Theme.Material.DayNight.DarkActionBar" parent="Theme.Material" />
-
- <!-- Variant of Material.DayNight with no action bar. -->
- <style name="Theme.Material.DayNight.NoActionBar" parent="Theme.Material.NoActionBar" />
-
- <!-- Variant of Material.DayNight that has no title bar and fills
- the entire screen. This theme
- sets {@link android.R.attr#windowFullscreen} to true. -->
- <style name="Theme.Material.DayNight.NoActionBar.Fullscreen" parent="Theme.Material.NoActionBar.Fullscreen" />
-
- <!-- Variant of Material.DayNight that has no title bar and fills
- the entire screen and extends into the display overscan region. This theme
- sets {@link android.R.attr#windowFullscreen} and {@link android.R.attr#windowOverscan}
- to true. -->
- <style name="Theme.Material.DayNight.NoActionBar.Overscan" parent="Theme.Material.NoActionBar.Overscan" />
-
- <!-- Variant of Material.DayNight that has no title bar and translucent
- system decor. This theme sets {@link android.R.attr#windowTranslucentStatus} and
- {@link android.R.attr#windowTranslucentNavigation} to true. -->
- <style name="Theme.Material.DayNight.NoActionBar.TranslucentDecor" parent="Theme.Material.NoActionBar.TranslucentDecor" />
-
- <!-- Default Material.DayNight theme for panel windows. This removes all extraneous
- window decorations, so you basically have an empty rectangle in which
- to place your content. It makes the window floating, with a transparent
- background, and turns off dimming behind the window. -->
- <style name="Theme.Material.DayNight.Panel" parent="Theme.Material.Panel" />
-
- <!-- Material theme (day/night version) for dialog windows and activities,
- which is used by the {@link android.app.Dialog} class. This changes
- the window to be floating (not fill the entire screen), and puts a
- frame around its contents. You can set this theme on an activity if
- you would like to make an activity that looks like a Dialog. -->
- <style name="Theme.Material.DayNight.Dialog" parent="Theme.Material.DayNight.BaseDialog" />
- <style name="Theme.Material.DayNight.BaseDialog" parent="Theme.Material.BaseDialog" />
-
- <!-- Variant of Theme.Material.DayNight.Dialog that has a nice minimum width for
- a regular dialog. -->
- <style name="Theme.Material.DayNight.Dialog.MinWidth" parent="Theme.Material.Dialog.MinWidth" />
-
- <!-- Variant of Theme.Material.DayNight.Dialog that does not include a title bar. -->
- <style name="Theme.Material.DayNight.Dialog.NoActionBar" parent="Theme.Material.Dialog.NoActionBar" />
-
- <!-- Variant of Theme.Material.DayNight.Dialog.NoActionBar that has a nice minimum width for
- a regular dialog. -->
- <style name="Theme.Material.DayNight.Dialog.NoActionBar.MinWidth" parent="Theme.Material.Dialog.NoActionBar.MinWidth" />
-
- <!-- Variant of Theme.Material.DayNight.Dialog that has a fixed size. -->
- <style name="Theme.Material.DayNight.Dialog.FixedSize" parent="Theme.Material.Dialog.FixedSize" />
-
- <!-- Variant of Theme.Material.DayNight.Dialog.NoActionBar that has a fixed size. -->
- <style name="Theme.Material.DayNight.Dialog.NoActionBar.FixedSize" parent="Theme.Material.Dialog.NoActionBar.FixedSize" />
-
- <!-- Theme for a window that will be displayed either full-screen on
- smaller screens (small, normal) or as a dialog on larger screens
- (large, xlarge). -->
- <style name="Theme.Material.DayNight.DialogWhenLarge" parent="Theme.Material.DialogWhenLarge" />
-
- <!-- Theme for a window with a dark action bar that will be displayed
- either full-screen on smaller screens (small, normal) or as a dialog
- on larger screens (large, xlarge). -->
- <style name="Theme.Material.DayNight.DialogWhenLarge.DarkActionBar" parent="Theme.Material.DialogWhenLarge" />
-
- <!-- Theme for a window without an action bar that will be displayed either full-screen
- on smaller screens (small, normal) or as a dialog on larger screens
- (large, xlarge). -->
- <style name="Theme.Material.DayNight.DialogWhenLarge.NoActionBar" parent="Theme.Material.DialogWhenLarge.NoActionBar" />
-
- <!-- Theme for a presentation window on a secondary display. -->
- <style name="Theme.Material.DayNight.Dialog.Presentation" parent="Theme.Material.Dialog.Presentation" />
-
- <!-- Material user theme for alert dialog windows, which is used by the
- {@link android.app.AlertDialog} class. -->
- <style name="Theme.Material.DayNight.Dialog.Alert" parent="Theme.Material.DayNight.Dialog.BaseAlert" />
- <style name="Theme.Material.DayNight.Dialog.BaseAlert" parent="Theme.Material.Dialog.BaseAlert" />
-
- <style name="Theme.Material.DayNight.SearchBar" parent="Theme.Material.SearchBar" />
- <style name="Theme.Material.DayNight.CompactMenu" parent="Theme.Material.CompactMenu" />
-
-</resources>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index e8279af7..3de8496 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -233,8 +233,8 @@
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Content verborgen op basis van beleid"</string>
<string name="safeMode" msgid="2788228061547930246">"Veilige modus"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android-systeem"</string>
- <string name="user_owner_label" msgid="2804351898001038951">"Persoonlijk"</string>
- <string name="managed_profile_label" msgid="6260850669674791528">"Werk"</string>
+ <string name="user_owner_label" msgid="1119010402169916617">"Overschakelen naar persoonlijk profiel"</string>
+ <string name="managed_profile_label" msgid="5289992269827577857">"Overschakelen naar werkprofiel"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"Contacten"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"toegang krijgen tot je contacten"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"Locatie"</string>
@@ -1045,7 +1045,8 @@
<string name="no_permissions" msgid="7283357728219338112">"Geen machtigingen vereist"</string>
<string name="perm_costs_money" msgid="4902470324142151116">"hieraan kunnen kosten zijn verbonden"</string>
<string name="dlg_ok" msgid="7376953167039865701">"OK"</string>
- <string name="usb_charging_notification_title" msgid="4004114449249406402">"USB voor opladen"</string>
+ <string name="usb_charging_notification_title" msgid="6895185153353640787">"Dit apparaat wordt opgeladen via USB"</string>
+ <string name="usb_supplying_notification_title" msgid="5310642257296510271">"Het aangesloten apparaat wordt via USB van voeding voorzien"</string>
<string name="usb_mtp_notification_title" msgid="8396264943589760855">"USB voor bestandsoverdacht"</string>
<string name="usb_ptp_notification_title" msgid="1347328437083192112">"USB voor foto-overdracht"</string>
<string name="usb_midi_notification_title" msgid="4850904915889144654">"USB voor MIDI"</string>
@@ -1060,11 +1061,10 @@
<string name="share_remote_bugreport_action" msgid="6249476773913384948">"DELEN"</string>
<string name="decline_remote_bugreport_action" msgid="6230987241608770062">"WEIGEREN"</string>
<string name="select_input_method" msgid="8547250819326693584">"Toetsenbord wijzigen"</string>
- <string name="configure_input_methods" msgid="5673193194563164021">"Andere toetsenborden"</string>
<string name="show_ime" msgid="2506087537466597099">"Dit op het scherm weergeven terwijl het fysieke toetsenbord actief is"</string>
<string name="hardware" msgid="194658061510127999">"Virtueel toetsenbord tonen"</string>
- <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Toetsenbordindeling selecteren"</string>
- <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Tik om een toetsenbordindeling te selecteren."</string>
+ <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Fysiek toetsenbord configureren"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Tik om een taal en indeling te selecteren"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"kandidaten"</u></string>
diff --git a/core/res/res/values-pa-rIN/strings.xml b/core/res/res/values-pa-rIN/strings.xml
index 8de9102..87f973f 100644
--- a/core/res/res/values-pa-rIN/strings.xml
+++ b/core/res/res/values-pa-rIN/strings.xml
@@ -233,8 +233,8 @@
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"ਨੀਤੀ ਦੁਆਰਾ ਸਮੱਗਰੀ ਲੁਕਾਈ ਗਈ"</string>
<string name="safeMode" msgid="2788228061547930246">"ਸੁਰੱਖਿਅਤ ਮੋਡ"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android System"</string>
- <string name="user_owner_label" msgid="2804351898001038951">"ਨਿੱਜੀ"</string>
- <string name="managed_profile_label" msgid="6260850669674791528">"ਕੰਮ"</string>
+ <string name="user_owner_label" msgid="1119010402169916617">"ਨਿੱਜੀ \'ਤੇ ਸਵਿੱਚ ਕਰੋ"</string>
+ <string name="managed_profile_label" msgid="5289992269827577857">"ਕੰਮ \'ਤੇ ਸਵਿੱਚ ਕਰੋ"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"ਸੰਪਰਕ"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"ਆਪਣੇ ਸੰਪਰਕਾਂ ਨੂੰ ਐਕਸੈਸ ਕਰੋ"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"ਨਿਰਧਾਰਿਤ ਸਥਾਨ"</string>
@@ -1045,7 +1045,8 @@
<string name="no_permissions" msgid="7283357728219338112">"ਕੋਈ ਅਨੁਮਤੀਆਂ ਲੁੜੀਂਦੀਆਂ ਨਹੀਂ"</string>
<string name="perm_costs_money" msgid="4902470324142151116">"ਇਸ ਨਾਲ ਤੁਹਾਨੂੰ ਖ਼ਰਚਾ ਪੈ ਸਕਦਾ ਹੈ"</string>
<string name="dlg_ok" msgid="7376953167039865701">"ਠੀਕ"</string>
- <string name="usb_charging_notification_title" msgid="4004114449249406402">"ਚਾਰਜਿੰਗ ਲਈ USB"</string>
+ <string name="usb_charging_notification_title" msgid="6895185153353640787">"ਇਹ ਡੀਵਾਈਸ USB ਰਾਹੀਂ ਚਾਰਜ ਕੀਤੀ ਜਾ ਰਹੀ ਹੈ"</string>
+ <string name="usb_supplying_notification_title" msgid="5310642257296510271">"ਨੱਥੀ ਕੀਤੀ ਡੀਵਾਈਸ ਨੂੰ USB ਰਾਹੀਂ ਪਾਵਰ ਮਿਲ ਰਹੀ ਹੈ"</string>
<string name="usb_mtp_notification_title" msgid="8396264943589760855">"ਫ਼ਾਈਲ ਟ੍ਰਾਂਸਫ਼ਰ ਲਈ USB"</string>
<string name="usb_ptp_notification_title" msgid="1347328437083192112">"ਫੋਟੋ ਟ੍ਰਾਂਸਫ਼ਰ ਲਈ USB"</string>
<string name="usb_midi_notification_title" msgid="4850904915889144654">"MIDI ਲਈ USB"</string>
@@ -1060,11 +1061,10 @@
<string name="share_remote_bugreport_action" msgid="6249476773913384948">"ਸਾਂਝੀ ਕਰੋ"</string>
<string name="decline_remote_bugreport_action" msgid="6230987241608770062">"ਅਸਵੀਕਾਰ ਕਰੋ"</string>
<string name="select_input_method" msgid="8547250819326693584">"ਕੀਬੋਰਡ ਬਦਲੋ"</string>
- <string name="configure_input_methods" msgid="5673193194563164021">"ਹੋਰ ਕੀ-ਬੋਰਡ"</string>
<string name="show_ime" msgid="2506087537466597099">"ਭੌਤਿਕ ਕੀ-ਬੋਰਡ ਸਰਗਰਮ ਹੋਣ ਦੌਰਾਨ ਇਸ ਨੂੰ ਸਕ੍ਰੀਨ \'ਤੇ ਬਣਾਈ ਰੱਖੋ"</string>
<string name="hardware" msgid="194658061510127999">"ਵਰਚੁਅਲ ਕੀ-ਬੋਰਡ ਵਿਖਾਓ"</string>
- <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"ਕੀਬੋਰਡ ਲੇਆਊਟ ਚੁਣੋ"</string>
- <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"ਇੱਕ ਕੀਬੋਰਡ ਲੇਆਊਟ ਚੁਣਨ ਲਈ ਛੋਹਵੋ।"</string>
+ <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"ਭੌਤਿਕ ਕੀ-ਬੋਰਡ ਦਾ ਸੰਰੂਪਣ ਕਰੋ"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"ਭਾਸ਼ਾ ਅਤੇ ਖਾਕਾ ਚੁਣਨ ਲਈ ਟੈਪ ਕਰੋ"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"ਉਮੀਦਵਾਰ"</u></string>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index f20e97d..6be9a9d 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -237,8 +237,8 @@
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Treść ukryta z powodu zasad"</string>
<string name="safeMode" msgid="2788228061547930246">"Tryb awaryjny"</string>
<string name="android_system_label" msgid="6577375335728551336">"System Android"</string>
- <string name="user_owner_label" msgid="2804351898001038951">"Osobiste"</string>
- <string name="managed_profile_label" msgid="6260850669674791528">"Praca"</string>
+ <string name="user_owner_label" msgid="1119010402169916617">"Włącz profil osobisty"</string>
+ <string name="managed_profile_label" msgid="5289992269827577857">"Włącz profil do pracy"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"Kontakty"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"dostęp do kontaktów"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"Lokalizacja"</string>
@@ -1061,7 +1061,8 @@
<string name="no_permissions" msgid="7283357728219338112">"Nie są wymagane żadne uprawnienia"</string>
<string name="perm_costs_money" msgid="4902470324142151116">"to może generować dodatkowe koszty"</string>
<string name="dlg_ok" msgid="7376953167039865701">"OK"</string>
- <string name="usb_charging_notification_title" msgid="4004114449249406402">"USB w trybie ładowania"</string>
+ <string name="usb_charging_notification_title" msgid="6895185153353640787">"Ładowanie urządzenia przez USB"</string>
+ <string name="usb_supplying_notification_title" msgid="5310642257296510271">"Zasilanie urządzenia przez USB"</string>
<string name="usb_mtp_notification_title" msgid="8396264943589760855">"USB w trybie przesyłania plików"</string>
<string name="usb_ptp_notification_title" msgid="1347328437083192112">"USB w trybie przesyłania zdjęć"</string>
<string name="usb_midi_notification_title" msgid="4850904915889144654">"USB w trybie MIDI"</string>
@@ -1076,11 +1077,10 @@
<string name="share_remote_bugreport_action" msgid="6249476773913384948">"UDOSTĘPNIJ"</string>
<string name="decline_remote_bugreport_action" msgid="6230987241608770062">"ODRZUĆ"</string>
<string name="select_input_method" msgid="8547250819326693584">"Zmień klawiaturę"</string>
- <string name="configure_input_methods" msgid="5673193194563164021">"Inne klawiatury"</string>
<string name="show_ime" msgid="2506087537466597099">"Pozostaw na ekranie, gdy aktywna jest klawiatura fizyczna"</string>
<string name="hardware" msgid="194658061510127999">"Pokaż klawiaturę wirtualną"</string>
- <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Wybierz układ klawiatury"</string>
- <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Kliknij, by wybrać układ klawiatury."</string>
+ <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Skonfiguruj klawiaturę fizyczną"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Kliknij, by wybrać język i układ"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" AĄBCĆDEĘFGHIJKLŁMNŃOÓPQRSŚTUVWXYZŹŻ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"kandydaci"</u></string>
diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml
index 2212f9f..c8004bf 100644
--- a/core/res/res/values-pt-rBR/strings.xml
+++ b/core/res/res/values-pt-rBR/strings.xml
@@ -233,8 +233,8 @@
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Conteúdo ocultado pela política"</string>
<string name="safeMode" msgid="2788228061547930246">"Modo de segurança"</string>
<string name="android_system_label" msgid="6577375335728551336">"Sistema Android"</string>
- <string name="user_owner_label" msgid="2804351898001038951">"Pessoal"</string>
- <string name="managed_profile_label" msgid="6260850669674791528">"Trabalho"</string>
+ <string name="user_owner_label" msgid="1119010402169916617">"Alternar para \"Pessoal\""</string>
+ <string name="managed_profile_label" msgid="5289992269827577857">"Alternar para \"Trabalho\""</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"Contatos"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"acesse seus contatos"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"Local"</string>
@@ -1045,7 +1045,8 @@
<string name="no_permissions" msgid="7283357728219338112">"Nenhuma permissão necessária"</string>
<string name="perm_costs_money" msgid="4902470324142151116">"isso pode lhe custar dinheiro"</string>
<string name="dlg_ok" msgid="7376953167039865701">"OK"</string>
- <string name="usb_charging_notification_title" msgid="4004114449249406402">"USB para carregamento"</string>
+ <string name="usb_charging_notification_title" msgid="6895185153353640787">"USB carregando este dispositivo"</string>
+ <string name="usb_supplying_notification_title" msgid="5310642257296510271">"USB fornecendo energia ao dispositivo conectado"</string>
<string name="usb_mtp_notification_title" msgid="8396264943589760855">"USB para transferência de arquivos"</string>
<string name="usb_ptp_notification_title" msgid="1347328437083192112">"USB para transferência de fotos"</string>
<string name="usb_midi_notification_title" msgid="4850904915889144654">"USB para MIDI"</string>
@@ -1060,11 +1061,10 @@
<string name="share_remote_bugreport_action" msgid="6249476773913384948">"COMPARTILHAR"</string>
<string name="decline_remote_bugreport_action" msgid="6230987241608770062">"RECUSAR"</string>
<string name="select_input_method" msgid="8547250819326693584">"Alterar teclado"</string>
- <string name="configure_input_methods" msgid="5673193194563164021">"Outros teclados"</string>
<string name="show_ime" msgid="2506087537466597099">"Manter na tela enquanto o teclado físico estiver ativo"</string>
<string name="hardware" msgid="194658061510127999">"Mostrar teclado virtual"</string>
- <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Selecione o layout de teclado"</string>
- <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Toque para selecionar um layout de teclado."</string>
+ <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Configurar teclado físico"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Toque para selecionar o idioma e o layout"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"candidatos"</u></string>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index 6cb94c3..c2ba8ad 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -233,8 +233,8 @@
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Conteúdo ocultado pela política"</string>
<string name="safeMode" msgid="2788228061547930246">"Modo seguro"</string>
<string name="android_system_label" msgid="6577375335728551336">"Sistema Android"</string>
- <string name="user_owner_label" msgid="2804351898001038951">"Pessoal"</string>
- <string name="managed_profile_label" msgid="6260850669674791528">"Trabalho"</string>
+ <string name="user_owner_label" msgid="1119010402169916617">"Mudar para pessoal"</string>
+ <string name="managed_profile_label" msgid="5289992269827577857">"Mudar para trabalho"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"Contactos"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"aceder aos contactos"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"Localização"</string>
@@ -1045,7 +1045,8 @@
<string name="no_permissions" msgid="7283357728219338112">"Não são necessárias permissões"</string>
<string name="perm_costs_money" msgid="4902470324142151116">"isto poderá estar sujeito a custos"</string>
<string name="dlg_ok" msgid="7376953167039865701">"OK"</string>
- <string name="usb_charging_notification_title" msgid="4004114449249406402">"USB para carregamento"</string>
+ <string name="usb_charging_notification_title" msgid="6895185153353640787">"Carregamento deste dispositivo por USB"</string>
+ <string name="usb_supplying_notification_title" msgid="5310642257296510271">"Fornecimento de energia ao dispositivo ligado por USB"</string>
<string name="usb_mtp_notification_title" msgid="8396264943589760855">"USB para transferência de ficheiros"</string>
<string name="usb_ptp_notification_title" msgid="1347328437083192112">"USB para transferência de fotos"</string>
<string name="usb_midi_notification_title" msgid="4850904915889144654">"USB para MIDI"</string>
@@ -1060,11 +1061,10 @@
<string name="share_remote_bugreport_action" msgid="6249476773913384948">"PARTILHAR"</string>
<string name="decline_remote_bugreport_action" msgid="6230987241608770062">"RECUSAR"</string>
<string name="select_input_method" msgid="8547250819326693584">"Alterar teclado"</string>
- <string name="configure_input_methods" msgid="5673193194563164021">"Outros teclados"</string>
<string name="show_ime" msgid="2506087537466597099">"Manter no ecrã enquanto o teclado físico estiver ativo"</string>
<string name="hardware" msgid="194658061510127999">"Mostrar o teclado virtual"</string>
- <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Selecionar esquema de teclado"</string>
- <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Toque para selecionar um esquema de teclado."</string>
+ <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Configurar teclado físico"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Toque para selecionar o idioma e o esquema"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"candidatos"</u></string>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index 2212f9f..c8004bf 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -233,8 +233,8 @@
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Conteúdo ocultado pela política"</string>
<string name="safeMode" msgid="2788228061547930246">"Modo de segurança"</string>
<string name="android_system_label" msgid="6577375335728551336">"Sistema Android"</string>
- <string name="user_owner_label" msgid="2804351898001038951">"Pessoal"</string>
- <string name="managed_profile_label" msgid="6260850669674791528">"Trabalho"</string>
+ <string name="user_owner_label" msgid="1119010402169916617">"Alternar para \"Pessoal\""</string>
+ <string name="managed_profile_label" msgid="5289992269827577857">"Alternar para \"Trabalho\""</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"Contatos"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"acesse seus contatos"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"Local"</string>
@@ -1045,7 +1045,8 @@
<string name="no_permissions" msgid="7283357728219338112">"Nenhuma permissão necessária"</string>
<string name="perm_costs_money" msgid="4902470324142151116">"isso pode lhe custar dinheiro"</string>
<string name="dlg_ok" msgid="7376953167039865701">"OK"</string>
- <string name="usb_charging_notification_title" msgid="4004114449249406402">"USB para carregamento"</string>
+ <string name="usb_charging_notification_title" msgid="6895185153353640787">"USB carregando este dispositivo"</string>
+ <string name="usb_supplying_notification_title" msgid="5310642257296510271">"USB fornecendo energia ao dispositivo conectado"</string>
<string name="usb_mtp_notification_title" msgid="8396264943589760855">"USB para transferência de arquivos"</string>
<string name="usb_ptp_notification_title" msgid="1347328437083192112">"USB para transferência de fotos"</string>
<string name="usb_midi_notification_title" msgid="4850904915889144654">"USB para MIDI"</string>
@@ -1060,11 +1061,10 @@
<string name="share_remote_bugreport_action" msgid="6249476773913384948">"COMPARTILHAR"</string>
<string name="decline_remote_bugreport_action" msgid="6230987241608770062">"RECUSAR"</string>
<string name="select_input_method" msgid="8547250819326693584">"Alterar teclado"</string>
- <string name="configure_input_methods" msgid="5673193194563164021">"Outros teclados"</string>
<string name="show_ime" msgid="2506087537466597099">"Manter na tela enquanto o teclado físico estiver ativo"</string>
<string name="hardware" msgid="194658061510127999">"Mostrar teclado virtual"</string>
- <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Selecione o layout de teclado"</string>
- <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Toque para selecionar um layout de teclado."</string>
+ <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Configurar teclado físico"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Toque para selecionar o idioma e o layout"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"candidatos"</u></string>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index 31ec3a0..7485e65 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -235,8 +235,8 @@
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Conținutul este ascuns conform politicii"</string>
<string name="safeMode" msgid="2788228061547930246">"Mod sigur"</string>
<string name="android_system_label" msgid="6577375335728551336">"Sistemul Android"</string>
- <string name="user_owner_label" msgid="2804351898001038951">"Personal"</string>
- <string name="managed_profile_label" msgid="6260850669674791528">"Serviciu"</string>
+ <string name="user_owner_label" msgid="1119010402169916617">"Comutați la Personal"</string>
+ <string name="managed_profile_label" msgid="5289992269827577857">"Comutați la Serviciu"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"Persoane de contact"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"acceseze persoanele de contact"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"Locație"</string>
@@ -1053,7 +1053,8 @@
<string name="no_permissions" msgid="7283357728219338112">"Nu se solicită nicio permisiune"</string>
<string name="perm_costs_money" msgid="4902470324142151116">"aceasta poate să genereze costuri"</string>
<string name="dlg_ok" msgid="7376953167039865701">"OK"</string>
- <string name="usb_charging_notification_title" msgid="4004114449249406402">"Conexiune USB pentru încărcare"</string>
+ <string name="usb_charging_notification_title" msgid="6895185153353640787">"Dispozitivul se încarcă prin USB"</string>
+ <string name="usb_supplying_notification_title" msgid="5310642257296510271">"Dispozitivul atașat se încarcă prin USB"</string>
<string name="usb_mtp_notification_title" msgid="8396264943589760855">"Conexiune USB pentru transferul fișierelor"</string>
<string name="usb_ptp_notification_title" msgid="1347328437083192112">"Conexiune USB pentru transferul fotografiilor"</string>
<string name="usb_midi_notification_title" msgid="4850904915889144654">"Conexiune USB pentru MIDI"</string>
@@ -1068,11 +1069,10 @@
<string name="share_remote_bugreport_action" msgid="6249476773913384948">"TRIMITEȚI"</string>
<string name="decline_remote_bugreport_action" msgid="6230987241608770062">"REFUZAȚI"</string>
<string name="select_input_method" msgid="8547250819326693584">"Schimbați tastatura"</string>
- <string name="configure_input_methods" msgid="5673193194563164021">"Alte tastaturi"</string>
<string name="show_ime" msgid="2506087537466597099">"Se păstrează pe ecran cât timp este activată tastatura fizică"</string>
<string name="hardware" msgid="194658061510127999">"Afișați tastatura virtuală"</string>
- <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Selectați aspectul tastaturii"</string>
- <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Atingeți pentru a selecta un aspect de tastatură."</string>
+ <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Configurați tastatura fizică"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Atingeți pentru a selecta limba și aspectul"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"candidați"</u></string>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index 5a79523..5926bfd 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -237,8 +237,8 @@
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Содержимое скрыто в соответствии с заданными правилами"</string>
<string name="safeMode" msgid="2788228061547930246">"Безопасный режим"</string>
<string name="android_system_label" msgid="6577375335728551336">"Система Android"</string>
- <string name="user_owner_label" msgid="2804351898001038951">"Личные данные"</string>
- <string name="managed_profile_label" msgid="6260850669674791528">"Работа"</string>
+ <string name="user_owner_label" msgid="1119010402169916617">"Перейти в личный профиль"</string>
+ <string name="managed_profile_label" msgid="5289992269827577857">"Перейти в рабочий профиль"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"Контакты"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"доступ к контактам"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"Местоположение"</string>
@@ -1061,7 +1061,8 @@
<string name="no_permissions" msgid="7283357728219338112">"Не требуется разрешений"</string>
<string name="perm_costs_money" msgid="4902470324142151116">"это может стоить вам денег!"</string>
<string name="dlg_ok" msgid="7376953167039865701">"ОК"</string>
- <string name="usb_charging_notification_title" msgid="4004114449249406402">"Зарядка через USB"</string>
+ <string name="usb_charging_notification_title" msgid="6895185153353640787">"Зарядка через USB"</string>
+ <string name="usb_supplying_notification_title" msgid="5310642257296510271">"Подача питания на подключенное устройство через USB"</string>
<string name="usb_mtp_notification_title" msgid="8396264943589760855">"Передача файлов через USB"</string>
<string name="usb_ptp_notification_title" msgid="1347328437083192112">"Передача фото через USB"</string>
<string name="usb_midi_notification_title" msgid="4850904915889144654">"MIDI через USB"</string>
@@ -1076,11 +1077,10 @@
<string name="share_remote_bugreport_action" msgid="6249476773913384948">"ПРЕДОСТАВИТЬ ДОСТУП"</string>
<string name="decline_remote_bugreport_action" msgid="6230987241608770062">"ОТКЛОНИТЬ"</string>
<string name="select_input_method" msgid="8547250819326693584">"Выбор раскладки"</string>
- <string name="configure_input_methods" msgid="5673193194563164021">"Другие клавиатуры"</string>
<string name="show_ime" msgid="2506087537466597099">"Показывать на экране, когда физическая клавиатура включена"</string>
<string name="hardware" msgid="194658061510127999">"Виртуальная клавиатура"</string>
- <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Выберите раскладку клавиатуры"</string>
- <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Нажмите, чтобы выбрать раскладку клавиатуры."</string>
+ <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Настройка физической клавиатуры"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Нажмите, чтобы выбрать язык и раскладку"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"варианты"</u></string>
diff --git a/core/res/res/values-si-rLK/strings.xml b/core/res/res/values-si-rLK/strings.xml
index 4f34cd0..6c76da0 100644
--- a/core/res/res/values-si-rLK/strings.xml
+++ b/core/res/res/values-si-rLK/strings.xml
@@ -233,8 +233,8 @@
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"ප්රතිපත්තිය විසින් අන්තර්ගතය සඟවන ලදී"</string>
<string name="safeMode" msgid="2788228061547930246">"ආරක්ෂිත ආකාරය"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android පද්ධතිය"</string>
- <string name="user_owner_label" msgid="2804351898001038951">"පෞද්ගලික"</string>
- <string name="managed_profile_label" msgid="6260850669674791528">"කාර්යාලය"</string>
+ <string name="user_owner_label" msgid="1119010402169916617">"පුද්ගලික වෙත මාරු වන්න"</string>
+ <string name="managed_profile_label" msgid="5289992269827577857">"කාර්යාලය වෙත මාරු වන්න"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"සම්බන්ධතා"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"ඔබේ සම්බන්ධතාවලට පිවිසෙන්න"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"ස්ථානය"</string>
@@ -1047,7 +1047,8 @@
<string name="no_permissions" msgid="7283357728219338112">"අවසර අවශ්ය නොමැත"</string>
<string name="perm_costs_money" msgid="4902470324142151116">"මෙමඟින් ඔබට මුදල් වැය විය හැක"</string>
<string name="dlg_ok" msgid="7376953167039865701">"හරි"</string>
- <string name="usb_charging_notification_title" msgid="4004114449249406402">"ආරෝපණය කිරීම සඳහා USB"</string>
+ <string name="usb_charging_notification_title" msgid="6895185153353640787">"මෙම උපාංගය USB වෙතින් ආරෝපණය"</string>
+ <string name="usb_supplying_notification_title" msgid="5310642257296510271">"අමුණා ඇති උපාංගයට USB මඟින් බලය සපයමින්"</string>
<string name="usb_mtp_notification_title" msgid="8396264943589760855">"ගොනු හුවමාරුව සඳහා USB"</string>
<string name="usb_ptp_notification_title" msgid="1347328437083192112">"ඡායාරූප හුවමාරුව සඳහා USB"</string>
<string name="usb_midi_notification_title" msgid="4850904915889144654">"MIDI සඳහා USB"</string>
@@ -1062,11 +1063,10 @@
<string name="share_remote_bugreport_action" msgid="6249476773913384948">"බෙදා ගන්න"</string>
<string name="decline_remote_bugreport_action" msgid="6230987241608770062">"ප්රතික්ෂේප කරන්න"</string>
<string name="select_input_method" msgid="8547250819326693584">"යතුරු පුවරු වෙනස් කිරීම"</string>
- <string name="configure_input_methods" msgid="5673193194563164021">"වෙනත් යතුරු පුවරු"</string>
<string name="show_ime" msgid="2506087537466597099">"භෞතික යතුරු පුවරුව සක්රිය අතරතුර එය තිරය මත තබා ගන්න"</string>
<string name="hardware" msgid="194658061510127999">"අතථ්ය යතුරු පුවරුව පෙන්වන්න"</string>
- <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"යතුරු පුවරුවට පිරිසැලැස්ම තෝරන්න"</string>
- <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"යතුරු පුවරුවට පිරිසැලැස්මක් තේරීමට ස්පර්ශ කරන්න."</string>
+ <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"භෞතික යතුරු පුවරුව වින්යාස කරන්න"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"භාෂාව හා පිරිසැලසුම තේරීමට තට්ටු කරන්න"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"අපේක්ෂකයන්"</u></string>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index 4ba64b1..ec45070 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -237,8 +237,8 @@
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Obsah je na základe pravidiel skrytý"</string>
<string name="safeMode" msgid="2788228061547930246">"Núdzový režim"</string>
<string name="android_system_label" msgid="6577375335728551336">"Systém Android"</string>
- <string name="user_owner_label" msgid="2804351898001038951">"Osobné"</string>
- <string name="managed_profile_label" msgid="6260850669674791528">"Práca"</string>
+ <string name="user_owner_label" msgid="1119010402169916617">"Prepnúť na osobný"</string>
+ <string name="managed_profile_label" msgid="5289992269827577857">"Prepnúť na pracovný"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"Kontakty"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"prístup k vašim kontaktom"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"Poloha"</string>
@@ -1061,7 +1061,8 @@
<string name="no_permissions" msgid="7283357728219338112">"Nevyžadujú sa žiadne oprávnenia."</string>
<string name="perm_costs_money" msgid="4902470324142151116">"môžu sa vám účtovať poplatky"</string>
<string name="dlg_ok" msgid="7376953167039865701">"OK"</string>
- <string name="usb_charging_notification_title" msgid="4004114449249406402">"USB na nabíjanie"</string>
+ <string name="usb_charging_notification_title" msgid="6895185153353640787">"Prebieha nabíjanie tohto zariadenia pomocou USB"</string>
+ <string name="usb_supplying_notification_title" msgid="5310642257296510271">"Prebieha nabíjanie pripojeného zariadenia pomocou USB"</string>
<string name="usb_mtp_notification_title" msgid="8396264943589760855">"USB na prenos súborov"</string>
<string name="usb_ptp_notification_title" msgid="1347328437083192112">"USB na prenos fotiek"</string>
<string name="usb_midi_notification_title" msgid="4850904915889144654">"USB na pripojenie zariadenia MIDI"</string>
@@ -1076,11 +1077,10 @@
<string name="share_remote_bugreport_action" msgid="6249476773913384948">"ZDIEĽAŤ"</string>
<string name="decline_remote_bugreport_action" msgid="6230987241608770062">"ODMIETNUŤ"</string>
<string name="select_input_method" msgid="8547250819326693584">"Zmeniť klávesnicu"</string>
- <string name="configure_input_methods" msgid="5673193194563164021">"Ďalšie klávesnice"</string>
<string name="show_ime" msgid="2506087537466597099">"Ponechať na obrazovke, keď je aktívna fyzická klávesnica"</string>
<string name="hardware" msgid="194658061510127999">"Zobraziť virtuálnu klávesnicu"</string>
- <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Zvoľte rozloženie klávesnice"</string>
- <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Dotykom zvoľte rozloženie klávesnice."</string>
+ <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Konfigurácia fyzickej klávesnice"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Klepnutím vyberte jazyk a rozloženie"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" AÁÄBCČDĎDZDŽEÉFGHCHIÍJKLĽMNŇOÓÔPRŔSŠTŤUÚVWXYÝZŽ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"kandidáti"</u></string>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index eb3d4e0..b2dba7e 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -237,8 +237,8 @@
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Pravilnik je skril vsebino"</string>
<string name="safeMode" msgid="2788228061547930246">"Varni način"</string>
<string name="android_system_label" msgid="6577375335728551336">"Sistem Android"</string>
- <string name="user_owner_label" msgid="2804351898001038951">"Osebno"</string>
- <string name="managed_profile_label" msgid="6260850669674791528">"Služba"</string>
+ <string name="user_owner_label" msgid="1119010402169916617">"Preklop na osebni profil"</string>
+ <string name="managed_profile_label" msgid="5289992269827577857">"Preklop na delovni profil"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"Stiki"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"dostop do stikov"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"Lokacija"</string>
@@ -1061,7 +1061,8 @@
<string name="no_permissions" msgid="7283357728219338112">"Ni zahtevanih dovoljenj"</string>
<string name="perm_costs_money" msgid="4902470324142151116">"to je lahko plačljivo"</string>
<string name="dlg_ok" msgid="7376953167039865701">"V redu"</string>
- <string name="usb_charging_notification_title" msgid="4004114449249406402">"USB za polnjenje"</string>
+ <string name="usb_charging_notification_title" msgid="6895185153353640787">"Polnjenje akumulatorja v napravi prek USB-ja"</string>
+ <string name="usb_supplying_notification_title" msgid="5310642257296510271">"Napajanje priključene naprave prek USB-ja"</string>
<string name="usb_mtp_notification_title" msgid="8396264943589760855">"USB za prenos datotek"</string>
<string name="usb_ptp_notification_title" msgid="1347328437083192112">"USB za prenos fotografij"</string>
<string name="usb_midi_notification_title" msgid="4850904915889144654">"USB za MIDI"</string>
@@ -1076,11 +1077,10 @@
<string name="share_remote_bugreport_action" msgid="6249476773913384948">"SKUPNA RABA"</string>
<string name="decline_remote_bugreport_action" msgid="6230987241608770062">"NE SPREJMEM"</string>
<string name="select_input_method" msgid="8547250819326693584">"Sprememba tipkovnice"</string>
- <string name="configure_input_methods" msgid="5673193194563164021">"Druge tipkovnice"</string>
<string name="show_ime" msgid="2506087537466597099">"Ohrani na zaslonu, dokler je aktivna fizična tipkovnica"</string>
<string name="hardware" msgid="194658061510127999">"Pokaži navidezno tipkovnico"</string>
- <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Izberite razporeditev tipkovnice"</string>
- <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Dotaknite se, da izberete razporeditev tipkovnice"</string>
+ <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Konfiguriranje fizične tipkovnice"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Dotaknite se, če želite izbrati jezik in postavitev."</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"kandidati"</u></string>
diff --git a/core/res/res/values-sq-rAL/strings.xml b/core/res/res/values-sq-rAL/strings.xml
index 94258e2..1846399 100644
--- a/core/res/res/values-sq-rAL/strings.xml
+++ b/core/res/res/values-sq-rAL/strings.xml
@@ -233,8 +233,8 @@
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Përmbajtja është e fshehur për shkak të politikës"</string>
<string name="safeMode" msgid="2788228061547930246">"Modaliteti i sigurisë"</string>
<string name="android_system_label" msgid="6577375335728551336">"Sistemi \"android\""</string>
- <string name="user_owner_label" msgid="2804351898001038951">"Personal"</string>
- <string name="managed_profile_label" msgid="6260850669674791528">"Puna"</string>
+ <string name="user_owner_label" msgid="1119010402169916617">"Ndryshoje te \"Personale\""</string>
+ <string name="managed_profile_label" msgid="5289992269827577857">"Ndryshoje te \"Puna\""</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"Kontaktet"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"qasu te kontaktet e tua"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"Vendndodhja"</string>
@@ -1045,7 +1045,8 @@
<string name="no_permissions" msgid="7283357728219338112">"Nuk kërkohen leje"</string>
<string name="perm_costs_money" msgid="4902470324142151116">"kjo mund të të kushtojë para"</string>
<string name="dlg_ok" msgid="7376953167039865701">"Në rregull"</string>
- <string name="usb_charging_notification_title" msgid="4004114449249406402">"USB-ja për ngarkim"</string>
+ <string name="usb_charging_notification_title" msgid="6895185153353640787">"Kjo pajisje ngarkohet me USB"</string>
+ <string name="usb_supplying_notification_title" msgid="5310642257296510271">"Pajisja e lidhur furnizohet me enrgji me USB"</string>
<string name="usb_mtp_notification_title" msgid="8396264943589760855">"USB për transferimin e skedarëve"</string>
<string name="usb_ptp_notification_title" msgid="1347328437083192112">"USB për transferimin e fotografive"</string>
<string name="usb_midi_notification_title" msgid="4850904915889144654">"USB për MIDI"</string>
@@ -1060,11 +1061,10 @@
<string name="share_remote_bugreport_action" msgid="6249476773913384948">"SHPËRNDA"</string>
<string name="decline_remote_bugreport_action" msgid="6230987241608770062">"REFUZO"</string>
<string name="select_input_method" msgid="8547250819326693584">"Ndërro tastierë"</string>
- <string name="configure_input_methods" msgid="5673193194563164021">"Tastierat e tjera"</string>
<string name="show_ime" msgid="2506087537466597099">"Mbaje në ekran ndërsa tastiera fizike është aktive"</string>
<string name="hardware" msgid="194658061510127999">"Shfaq tastierën virtuale"</string>
- <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Përzgjidh planin e tastierës"</string>
- <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Prek për të përzgjedhur tastierën."</string>
+ <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Konfiguro tastierën fizike"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Trokit për të zgjedhur gjuhën dhe strukturën"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"kandidatë"</u></string>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index bfc22e4..2112dbb 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -235,8 +235,8 @@
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Садржај је сакривен смерницама"</string>
<string name="safeMode" msgid="2788228061547930246">"Безбедни режим"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android систем"</string>
- <string name="user_owner_label" msgid="2804351898001038951">"Лично"</string>
- <string name="managed_profile_label" msgid="6260850669674791528">"Посао"</string>
+ <string name="user_owner_label" msgid="1119010402169916617">"Пређи на Лични профил"</string>
+ <string name="managed_profile_label" msgid="5289992269827577857">"Пређи на профил за Work"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"Контакти"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"приступи контактима"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"Локација"</string>
@@ -1053,7 +1053,8 @@
<string name="no_permissions" msgid="7283357728219338112">"Није потребна ниједна дозвола"</string>
<string name="perm_costs_money" msgid="4902470324142151116">"ово ће вам можда бити наплаћено"</string>
<string name="dlg_ok" msgid="7376953167039865701">"Потврди"</string>
- <string name="usb_charging_notification_title" msgid="4004114449249406402">"USB за пуњење"</string>
+ <string name="usb_charging_notification_title" msgid="6895185153353640787">"USB пуни овај уређај"</string>
+ <string name="usb_supplying_notification_title" msgid="5310642257296510271">"USB снабдева енергијом прикључени уређај"</string>
<string name="usb_mtp_notification_title" msgid="8396264943589760855">"USB за пренос датотека"</string>
<string name="usb_ptp_notification_title" msgid="1347328437083192112">"USB за пренос слика"</string>
<string name="usb_midi_notification_title" msgid="4850904915889144654">"USB за MIDI"</string>
@@ -1068,11 +1069,10 @@
<string name="share_remote_bugreport_action" msgid="6249476773913384948">"ДЕЛИ"</string>
<string name="decline_remote_bugreport_action" msgid="6230987241608770062">"ОДБИЈ"</string>
<string name="select_input_method" msgid="8547250819326693584">"Промените тастатуру"</string>
- <string name="configure_input_methods" msgid="5673193194563164021">"Друге тастатуре"</string>
<string name="show_ime" msgid="2506087537466597099">"Задржи га на екрану док је физичка тастатура активна"</string>
<string name="hardware" msgid="194658061510127999">"Прикажи виртуелну тастатуру"</string>
- <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Избор распореда тастатуре"</string>
- <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Додирните да бисте изабрали распоред тастатуре."</string>
+ <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Конфигуришите физичку тастатуру"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Додирните да бисте изабрали језик и распоред"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"кандидати"</u></string>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index 3f2a4a3..832d4a2 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -233,8 +233,8 @@
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Innehåll har dolts p.g.a. en policy"</string>
<string name="safeMode" msgid="2788228061547930246">"Säkert läge"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android-system"</string>
- <string name="user_owner_label" msgid="2804351898001038951">"Personligt"</string>
- <string name="managed_profile_label" msgid="6260850669674791528">"Arbetet"</string>
+ <string name="user_owner_label" msgid="1119010402169916617">"Byt till din personliga profil"</string>
+ <string name="managed_profile_label" msgid="5289992269827577857">"Byt till jobbprofilen"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"Kontakter"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"få tillgång till dina kontakter"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"Plats"</string>
@@ -1045,7 +1045,8 @@
<string name="no_permissions" msgid="7283357728219338112">"Inga behörigheter krävs"</string>
<string name="perm_costs_money" msgid="4902470324142151116">"detta kan kosta pengar"</string>
<string name="dlg_ok" msgid="7376953167039865701">"OK"</string>
- <string name="usb_charging_notification_title" msgid="4004114449249406402">"USB för laddning"</string>
+ <string name="usb_charging_notification_title" msgid="6895185153353640787">"Enheten laddas via USB"</string>
+ <string name="usb_supplying_notification_title" msgid="5310642257296510271">"En ansluten enhet strömförsörjs via USB"</string>
<string name="usb_mtp_notification_title" msgid="8396264943589760855">"USB för överföring av filer"</string>
<string name="usb_ptp_notification_title" msgid="1347328437083192112">"USB för överföring av foton"</string>
<string name="usb_midi_notification_title" msgid="4850904915889144654">"USB för MIDI"</string>
@@ -1060,11 +1061,10 @@
<string name="share_remote_bugreport_action" msgid="6249476773913384948">"DELA"</string>
<string name="decline_remote_bugreport_action" msgid="6230987241608770062">"AVVISA"</string>
<string name="select_input_method" msgid="8547250819326693584">"Byt tangentbord"</string>
- <string name="configure_input_methods" msgid="5673193194563164021">"Andra tangentbord"</string>
<string name="show_ime" msgid="2506087537466597099">"Ha kvar den på skärmen när det fysiska tangentbordet används"</string>
<string name="hardware" msgid="194658061510127999">"Visa virtuellt tangentbord"</string>
- <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Välj en tangentbordslayout"</string>
- <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Välj en tangentbordslayout genom att trycka."</string>
+ <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Konfigurera fysiskt tangentbord"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Tryck om du vill välja språk och layout"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"kandidater"</u></string>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index 2e1a7a4..e0a32f6 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -235,8 +235,8 @@
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Maudhui yamefichwa kulingana na sera"</string>
<string name="safeMode" msgid="2788228061547930246">"Mtindo salama"</string>
<string name="android_system_label" msgid="6577375335728551336">"Mfumo wa Android"</string>
- <string name="user_owner_label" msgid="2804351898001038951">"Binafsi"</string>
- <string name="managed_profile_label" msgid="6260850669674791528">"Kazini"</string>
+ <string name="user_owner_label" msgid="1119010402169916617">"Badili uweke wasifu wa Binafsi"</string>
+ <string name="managed_profile_label" msgid="5289992269827577857">"Badili uweke wasifu wa Kazini"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"Anwani"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"ifikie anwani zako"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"Mahali"</string>
@@ -1047,7 +1047,8 @@
<string name="no_permissions" msgid="7283357728219338112">"Hakuna vibali vinavyohitajika"</string>
<string name="perm_costs_money" msgid="4902470324142151116">"huenda hii ikakugharimu pesa"</string>
<string name="dlg_ok" msgid="7376953167039865701">"Sawa"</string>
- <string name="usb_charging_notification_title" msgid="4004114449249406402">"USB kwa ajili ya kuchaji"</string>
+ <string name="usb_charging_notification_title" msgid="6895185153353640787">"Unachaji kifaa hiki ukitumia USB"</string>
+ <string name="usb_supplying_notification_title" msgid="5310642257296510271">"USB inachaji kifaa ulichounganisha"</string>
<string name="usb_mtp_notification_title" msgid="8396264943589760855">"USB kwa ajili ya kuhamisha faili"</string>
<string name="usb_ptp_notification_title" msgid="1347328437083192112">"USB kwa ajili ya kuhamisha picha"</string>
<string name="usb_midi_notification_title" msgid="4850904915889144654">"USB kwa ajili ya MIDI"</string>
@@ -1062,11 +1063,10 @@
<string name="share_remote_bugreport_action" msgid="6249476773913384948">"SHIRIKI"</string>
<string name="decline_remote_bugreport_action" msgid="6230987241608770062">"KATAA"</string>
<string name="select_input_method" msgid="8547250819326693584">"Badilisha kibodi"</string>
- <string name="configure_input_methods" msgid="5673193194563164021">"Kibodi zingine"</string>
<string name="show_ime" msgid="2506087537466597099">"Iweke kwenye skrini wakati kibodi inapotumika"</string>
<string name="hardware" msgid="194658061510127999">"Onyesha kibodi pepe"</string>
- <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Teua mpangilio wa kibodi"</string>
- <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Gusa ili kuchagua mpangilio wa kibodi."</string>
+ <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Sanidi kibodi halisi"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Gonga ili uchague lugha na muundo"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"wagombeaji"</u></string>
diff --git a/core/res/res/values-sw600dp/dimens_material.xml b/core/res/res/values-sw600dp/dimens_material.xml
index 3bbb352..1ec5c0f 100644
--- a/core/res/res/values-sw600dp/dimens_material.xml
+++ b/core/res/res/values-sw600dp/dimens_material.xml
@@ -23,6 +23,8 @@
<dimen name="action_bar_default_height_material">64dp</dimen>
<!-- Default content inset of an action bar. -->
<dimen name="action_bar_content_inset_material">24dp</dimen>
+ <!-- Default content inset of an action bar with navigation present. -->
+ <dimen name="action_bar_content_inset_with_nav">80dp</dimen>
<!-- Default start padding of an action bar. -->
<dimen name="action_bar_default_padding_start_material">8dp</dimen>
diff --git a/core/res/res/values-ta-rIN/strings.xml b/core/res/res/values-ta-rIN/strings.xml
index b34caed..773301f 100644
--- a/core/res/res/values-ta-rIN/strings.xml
+++ b/core/res/res/values-ta-rIN/strings.xml
@@ -233,8 +233,8 @@
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"கொள்கையின்படி உள்ளடக்கம் மறைக்கப்பட்டது"</string>
<string name="safeMode" msgid="2788228061547930246">"பாதுகாப்பு பயன்முறை"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android அமைப்பு"</string>
- <string name="user_owner_label" msgid="2804351898001038951">"தனிப்பட்ட"</string>
- <string name="managed_profile_label" msgid="6260850669674791528">"பணியிடம்"</string>
+ <string name="user_owner_label" msgid="1119010402169916617">"தனிப்பட்ட சுயவிவரத்திற்கு மாறு"</string>
+ <string name="managed_profile_label" msgid="5289992269827577857">"பணிச் சுயவிவரத்திற்கு மாறு"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"தொடர்புகள்"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"தொடர்புகளை அணுகும்"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"இருப்பிடம்"</string>
@@ -1045,7 +1045,8 @@
<string name="no_permissions" msgid="7283357728219338112">"அனுமதிகள் தேவையில்லை"</string>
<string name="perm_costs_money" msgid="4902470324142151116">"இதனால் நீங்கள் கட்டணம் செலுத்த வேண்டியிருக்கலாம்"</string>
<string name="dlg_ok" msgid="7376953167039865701">"சரி"</string>
- <string name="usb_charging_notification_title" msgid="4004114449249406402">"USB, சார்ஜ் செய்வதற்கு மட்டும்"</string>
+ <string name="usb_charging_notification_title" msgid="6895185153353640787">"இந்தச் சாதனத்தை USB சார்ஜ் செய்கிறது"</string>
+ <string name="usb_supplying_notification_title" msgid="5310642257296510271">"இணைத்துள்ள சாதனத்திற்கு USB சக்தி அளிக்கிறது"</string>
<string name="usb_mtp_notification_title" msgid="8396264943589760855">"USB, கோப்புப் பரிமாற்றத்துக்கு மட்டும்"</string>
<string name="usb_ptp_notification_title" msgid="1347328437083192112">"USB, படப் பரிமாற்றத்துக்கு மட்டும்"</string>
<string name="usb_midi_notification_title" msgid="4850904915889144654">"USB, MIDIக்கு மட்டும்"</string>
@@ -1060,11 +1061,10 @@
<string name="share_remote_bugreport_action" msgid="6249476773913384948">"பகிர்"</string>
<string name="decline_remote_bugreport_action" msgid="6230987241608770062">"வேண்டாம்"</string>
<string name="select_input_method" msgid="8547250819326693584">"விசைப்பலகையை மாற்று"</string>
- <string name="configure_input_methods" msgid="5673193194563164021">"பிற விசைப்பலகைகள்"</string>
<string name="show_ime" msgid="2506087537466597099">"கைமுறை விசைப்பலகை இயக்கத்தில் இருக்கும் போது IMEஐ திரையில் வைத்திரு"</string>
<string name="hardware" msgid="194658061510127999">"விர்ச்சுவல் விசைப்பலகையை காட்டு"</string>
- <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"விசைப்பலகைத் தளவமைப்பைத் தேர்ந்தெடுக்கவும்"</string>
- <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"விசைப்பலகைத் தளவமைப்பைத் தேர்ந்தெடுக்க தொடவும்."</string>
+ <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"கைமுறை விசைப்பலகையை உள்ளமைக்கவும்"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"மொழியையும் தளவமைப்பையும் தேர்ந்தெடுக்க, தட்டவும்"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"கேன்டிடேட்ஸ்"</u></string>
diff --git a/core/res/res/values-te-rIN/strings.xml b/core/res/res/values-te-rIN/strings.xml
index 9beb1e1..4809c98 100644
--- a/core/res/res/values-te-rIN/strings.xml
+++ b/core/res/res/values-te-rIN/strings.xml
@@ -233,8 +233,8 @@
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"విధానం ద్వారా కంటెంట్లు దాచబడ్డాయి"</string>
<string name="safeMode" msgid="2788228061547930246">"సురక్షిత మోడ్"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android సిస్టమ్"</string>
- <string name="user_owner_label" msgid="2804351898001038951">"వ్యక్తిగతం"</string>
- <string name="managed_profile_label" msgid="6260850669674791528">"కార్యాలయం"</string>
+ <string name="user_owner_label" msgid="1119010402169916617">"వ్యక్తిగతానికి మార్చు"</string>
+ <string name="managed_profile_label" msgid="5289992269827577857">"కార్యాలయానికి మార్చు"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"పరిచయాలు"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"మీ పరిచయాలను ప్రాప్యత చేయడానికి"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"స్థానం"</string>
@@ -1045,7 +1045,8 @@
<string name="no_permissions" msgid="7283357728219338112">"అనుమతులు అవసరం లేదు"</string>
<string name="perm_costs_money" msgid="4902470324142151116">"దీనికి మీకు డబ్బు ఖర్చు కావచ్చు"</string>
<string name="dlg_ok" msgid="7376953167039865701">"సరే"</string>
- <string name="usb_charging_notification_title" msgid="4004114449249406402">"ఛార్జింగ్ కోసం USB"</string>
+ <string name="usb_charging_notification_title" msgid="6895185153353640787">"ఈ పరికరం USB మోడ్లో ఛార్జ్ అవుతోంది"</string>
+ <string name="usb_supplying_notification_title" msgid="5310642257296510271">"జోడించిన పరికరానికి USB ద్వారా పవర్ సరఫరా అవుతోంది"</string>
<string name="usb_mtp_notification_title" msgid="8396264943589760855">"ఫైల్ బదిలీ కోసం USB"</string>
<string name="usb_ptp_notification_title" msgid="1347328437083192112">"ఫోటో బదిలీ కోసం USB"</string>
<string name="usb_midi_notification_title" msgid="4850904915889144654">"MIDI కోసం USB"</string>
@@ -1060,11 +1061,10 @@
<string name="share_remote_bugreport_action" msgid="6249476773913384948">"భాగస్వామ్యం చేయి"</string>
<string name="decline_remote_bugreport_action" msgid="6230987241608770062">"తిరస్కరిస్తున్నాను"</string>
<string name="select_input_method" msgid="8547250819326693584">"కీబోర్డ్ను మార్చు"</string>
- <string name="configure_input_methods" msgid="5673193194563164021">"ఇతర కీబోర్డ్లు"</string>
<string name="show_ime" msgid="2506087537466597099">"దీన్ని భౌతిక కీబోర్డ్ సక్రియంగా ఉన్నప్పుడు స్క్రీన్పై ఉంచుతుంది"</string>
<string name="hardware" msgid="194658061510127999">"వర్చువల్ కీబోర్డ్ను చూపు"</string>
- <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"కీబోర్డ్ లేఅవుట్ను ఎంచుకోండి"</string>
- <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"కీబోర్డ్ లేఅవుట్ను ఎంచుకోవడానికి తాకండి."</string>
+ <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"భౌతిక కీబోర్డుని కాన్ఫిగర్ చేయండి"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"భాష మరియు లేఅవుట్ను ఎంచుకోవడానికి నొక్కండి"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"క్యాండిడేట్లు"</u></string>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index d0b6f43..0ea2e52 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -233,8 +233,8 @@
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"มีการซ่อนเนื้อหาโดยนโยบาย"</string>
<string name="safeMode" msgid="2788228061547930246">"โหมดปลอดภัย"</string>
<string name="android_system_label" msgid="6577375335728551336">"ระบบ Android"</string>
- <string name="user_owner_label" msgid="2804351898001038951">"ส่วนตัว"</string>
- <string name="managed_profile_label" msgid="6260850669674791528">"ที่ทำงาน"</string>
+ <string name="user_owner_label" msgid="1119010402169916617">"เปลี่ยนไปใช้โปรไฟล์ส่วนตัว"</string>
+ <string name="managed_profile_label" msgid="5289992269827577857">"เปลี่ยนไปใช้โปรไฟล์งาน"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"รายชื่อติดต่อ"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"เข้าถึงรายชื่อติดต่อ"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"ตำแหน่ง"</string>
@@ -1045,7 +1045,8 @@
<string name="no_permissions" msgid="7283357728219338112">"ไม่ต้องการการอนุญาต"</string>
<string name="perm_costs_money" msgid="4902470324142151116">"รายการนี้อาจมีการเรียกเก็บเงิน"</string>
<string name="dlg_ok" msgid="7376953167039865701">"ตกลง"</string>
- <string name="usb_charging_notification_title" msgid="4004114449249406402">"USB สำหรับการชาร์จ"</string>
+ <string name="usb_charging_notification_title" msgid="6895185153353640787">"กำลังชาร์จอุปกรณ์นี้ด้วย USB"</string>
+ <string name="usb_supplying_notification_title" msgid="5310642257296510271">"กำลังจ่ายไฟให้อุปกรณ์ที่เชื่อมต่ออยู่ผ่าน USB"</string>
<string name="usb_mtp_notification_title" msgid="8396264943589760855">"USB สำหรับการโอนไฟล์"</string>
<string name="usb_ptp_notification_title" msgid="1347328437083192112">"USB สำหรับการโอนรูปภาพ"</string>
<string name="usb_midi_notification_title" msgid="4850904915889144654">"USB สำหรับ MIDI"</string>
@@ -1060,11 +1061,10 @@
<string name="share_remote_bugreport_action" msgid="6249476773913384948">"แชร์"</string>
<string name="decline_remote_bugreport_action" msgid="6230987241608770062">"ปฏิเสธ"</string>
<string name="select_input_method" msgid="8547250819326693584">"เปลี่ยนแป้นพิมพ์"</string>
- <string name="configure_input_methods" msgid="5673193194563164021">"แป้นพิมพ์อื่นๆ"</string>
<string name="show_ime" msgid="2506087537466597099">"เปิดทิ้งไว้บนหน้าจอในระหว่างใช้งานแป้นพิมพ์จริง"</string>
<string name="hardware" msgid="194658061510127999">"แสดงแป้นพิมพ์เสมือน"</string>
- <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"เลือกรูปแบบแป้นพิมพ์"</string>
- <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"แตะเพื่อเลือกรูปแบบแป้นพิมพ์"</string>
+ <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"กำหนดค่าแป้นพิมพ์จริง"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"แตะเพื่อเลือกภาษาและรูปแบบ"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" กขฃคฅฆงจฉชซฌญฎฏฐฑฒณดตถทธนบปผฝพฟภมยรลวศษสหฬอฮ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" กขฃคฅฆงจฉชซฌญฎฏฐฑฒณดตถทธนบปผฝพฟภมยรลวศษสหฬอฮ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"ตัวเลือก"</u></string>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index 698ae61..00918a4 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -233,8 +233,8 @@
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Itinago ang mga content alinsunod sa patakaran"</string>
<string name="safeMode" msgid="2788228061547930246">"Safe mode"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android System"</string>
- <string name="user_owner_label" msgid="2804351898001038951">"Personal"</string>
- <string name="managed_profile_label" msgid="6260850669674791528">"Trabaho"</string>
+ <string name="user_owner_label" msgid="1119010402169916617">"Lumipat sa Personal"</string>
+ <string name="managed_profile_label" msgid="5289992269827577857">"Lumipat sa para sa Trabaho"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"Mga Contact"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"ina-access ang iyong mga contact"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"Lokasyon"</string>
@@ -1045,7 +1045,8 @@
<string name="no_permissions" msgid="7283357728219338112">"Walang mga kinakailangang pahintulot"</string>
<string name="perm_costs_money" msgid="4902470324142151116">"maaari itong magdulot ng gastos sa iyo"</string>
<string name="dlg_ok" msgid="7376953167039865701">"OK"</string>
- <string name="usb_charging_notification_title" msgid="4004114449249406402">"USB para sa pagcha-charge"</string>
+ <string name="usb_charging_notification_title" msgid="6895185153353640787">"China-charge sa USB ang device na ito"</string>
+ <string name="usb_supplying_notification_title" msgid="5310642257296510271">"USB ang nagbibigay ng power sa nakakabit na device"</string>
<string name="usb_mtp_notification_title" msgid="8396264943589760855">"USB para sa paglipat ng file"</string>
<string name="usb_ptp_notification_title" msgid="1347328437083192112">"USB para sa paglipat ng larawan"</string>
<string name="usb_midi_notification_title" msgid="4850904915889144654">"USB para sa MIDI"</string>
@@ -1060,11 +1061,10 @@
<string name="share_remote_bugreport_action" msgid="6249476773913384948">"IBAHAGI"</string>
<string name="decline_remote_bugreport_action" msgid="6230987241608770062">"TANGGIHAN"</string>
<string name="select_input_method" msgid="8547250819326693584">"Baguhin ang keyboard"</string>
- <string name="configure_input_methods" msgid="5673193194563164021">"Iba pang mga keyboard"</string>
<string name="show_ime" msgid="2506087537466597099">"Panatilihin ito sa screen habang aktibo ang pisikal na keyboard"</string>
<string name="hardware" msgid="194658061510127999">"Ipakita ang virtual keyboard"</string>
- <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Pumili ng layout ng keyboard"</string>
- <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Pindutin upang pumili ng layout ng keyboard."</string>
+ <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"I-configure ang pisikal na keyboard"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"I-tap upang pumili ng wika at layout"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"mga kandidato"</u></string>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index 52c32e7..4db8264 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -233,8 +233,8 @@
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"İçerikler politika nedeniyle gizlendi"</string>
<string name="safeMode" msgid="2788228061547930246">"Güvenli mod"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android Sistemi"</string>
- <string name="user_owner_label" msgid="2804351898001038951">"Kişisel"</string>
- <string name="managed_profile_label" msgid="6260850669674791528">"İş"</string>
+ <string name="user_owner_label" msgid="1119010402169916617">"Kişisel Profile Geç"</string>
+ <string name="managed_profile_label" msgid="5289992269827577857">"İş Profiline Geç"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"Kişiler"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"kişilerinize erişme"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"Konum"</string>
@@ -1045,7 +1045,8 @@
<string name="no_permissions" msgid="7283357728219338112">"İzin gerektirmez"</string>
<string name="perm_costs_money" msgid="4902470324142151116">"bunun için sizden ücret alınabilir"</string>
<string name="dlg_ok" msgid="7376953167039865701">"Tamam"</string>
- <string name="usb_charging_notification_title" msgid="4004114449249406402">"Şarj için USB"</string>
+ <string name="usb_charging_notification_title" msgid="6895185153353640787">"Bu cihaz USB\'den şarj oluyor"</string>
+ <string name="usb_supplying_notification_title" msgid="5310642257296510271">"USB, bağlı cihaza güç sağlıyor"</string>
<string name="usb_mtp_notification_title" msgid="8396264943589760855">"Dosya aktarımı için USB"</string>
<string name="usb_ptp_notification_title" msgid="1347328437083192112">"Fotoğraf aktarımı için USB"</string>
<string name="usb_midi_notification_title" msgid="4850904915889144654">"MIDI için USB"</string>
@@ -1060,11 +1061,10 @@
<string name="share_remote_bugreport_action" msgid="6249476773913384948">"PAYLAŞ"</string>
<string name="decline_remote_bugreport_action" msgid="6230987241608770062">"REDDET"</string>
<string name="select_input_method" msgid="8547250819326693584">"Klavyeyi değiştir"</string>
- <string name="configure_input_methods" msgid="5673193194563164021">"Diğer klavyeler"</string>
<string name="show_ime" msgid="2506087537466597099">"Fiziksel klavye etkin durumdayken ekranda tut"</string>
<string name="hardware" msgid="194658061510127999">"Sanal klavyeyi göster"</string>
- <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Klavye düzeni seçin"</string>
- <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Bir klavye düzeni seçmek için dokunun."</string>
+ <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Fiziksel klavyeyi yapılandırın"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Dili ve düzeni seçmek için hafifçe dokunun"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"adaylar"</u></string>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index 8142aa0..fe7be12 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -237,8 +237,8 @@
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Вміст сховано згідно з правилом"</string>
<string name="safeMode" msgid="2788228061547930246">"Безп. режим"</string>
<string name="android_system_label" msgid="6577375335728551336">"Система Android"</string>
- <string name="user_owner_label" msgid="2804351898001038951">"Особисті дані"</string>
- <string name="managed_profile_label" msgid="6260850669674791528">"Службовий профіль"</string>
+ <string name="user_owner_label" msgid="1119010402169916617">"Перейти в особистий профіль"</string>
+ <string name="managed_profile_label" msgid="5289992269827577857">"Перейти в робочий профіль"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"Контакти"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"отримувати доступ до контактів"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"Геодані"</string>
@@ -1061,7 +1061,8 @@
<string name="no_permissions" msgid="7283357728219338112">"Дозвіл не потрібний"</string>
<string name="perm_costs_money" msgid="4902470324142151116">"це платна послуга"</string>
<string name="dlg_ok" msgid="7376953167039865701">"OK"</string>
- <string name="usb_charging_notification_title" msgid="4004114449249406402">"USB для заряджання"</string>
+ <string name="usb_charging_notification_title" msgid="6895185153353640787">"USB-кабель, через який заряджається цей пристрій"</string>
+ <string name="usb_supplying_notification_title" msgid="5310642257296510271">"USB-кабель, через який живиться під’єднаний пристрій"</string>
<string name="usb_mtp_notification_title" msgid="8396264943589760855">"USB для перенесення файлів"</string>
<string name="usb_ptp_notification_title" msgid="1347328437083192112">"USB для перенесення фотографій"</string>
<string name="usb_midi_notification_title" msgid="4850904915889144654">"USB для режиму MIDI"</string>
@@ -1076,11 +1077,10 @@
<string name="share_remote_bugreport_action" msgid="6249476773913384948">"ПОДІЛИТИСЯ"</string>
<string name="decline_remote_bugreport_action" msgid="6230987241608770062">"ВІДХИЛИТИ"</string>
<string name="select_input_method" msgid="8547250819326693584">"Змінити клавіатуру"</string>
- <string name="configure_input_methods" msgid="5673193194563164021">"Інші клавіатури"</string>
<string name="show_ime" msgid="2506087537466597099">"Утримуйте на екрані, коли активна фізична клавіатура"</string>
<string name="hardware" msgid="194658061510127999">"Показати віртуальну клавіатуру"</string>
- <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Виберіть розкладку клавіатури"</string>
- <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Торкніться, щоб вибрати розкладку клавіатури."</string>
+ <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Налаштуйте фізичну клавіатуру"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Торкніться, щоб вибрати мову та розкладку"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" АБВГҐДЕЄЖЗИІЇЙКЛМНОПРСТУФХЦЧШЩЬЮЯ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789АБВГҐДЕЄЖЗИІЇЙКЛМНОПРСТУФХЦЧШЩЬЮЯ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"кандидати"</u></string>
diff --git a/core/res/res/values-ur-rPK/strings.xml b/core/res/res/values-ur-rPK/strings.xml
index 41a1e82..5236b7f 100644
--- a/core/res/res/values-ur-rPK/strings.xml
+++ b/core/res/res/values-ur-rPK/strings.xml
@@ -233,8 +233,8 @@
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"مواد پالیسی کے تحت مخفی ہے"</string>
<string name="safeMode" msgid="2788228061547930246">"حفاظتی وضع"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android سسٹم"</string>
- <string name="user_owner_label" msgid="2804351898001038951">"ذاتی"</string>
- <string name="managed_profile_label" msgid="6260850669674791528">"دفتر"</string>
+ <string name="user_owner_label" msgid="1119010402169916617">"ذاتی پر سوئچ کریں"</string>
+ <string name="managed_profile_label" msgid="5289992269827577857">"کام پر سوئچ کریں"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"رابطے"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"اپنے رابطوں تک رسائی حاصل کریں"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"مقام"</string>
@@ -1045,7 +1045,8 @@
<string name="no_permissions" msgid="7283357728219338112">"کوئی اجازتیں درکار نہیں ہیں"</string>
<string name="perm_costs_money" msgid="4902470324142151116">"اس میں آپ کا پیسہ خرچ ہو سکتا ہے"</string>
<string name="dlg_ok" msgid="7376953167039865701">"ٹھیک ہے"</string>
- <string name="usb_charging_notification_title" msgid="4004114449249406402">"چارجنگ کیلئے USB"</string>
+ <string name="usb_charging_notification_title" msgid="6895185153353640787">"USB اس آلے کو چارج کر رہی ہے"</string>
+ <string name="usb_supplying_notification_title" msgid="5310642257296510271">"منسلکہ آلے کو USB پاور سپلائی کر رہی ہے"</string>
<string name="usb_mtp_notification_title" msgid="8396264943589760855">"فائل کی منتقلی کیلئے USB"</string>
<string name="usb_ptp_notification_title" msgid="1347328437083192112">"تصویر کی منتقلی کیلئے USB"</string>
<string name="usb_midi_notification_title" msgid="4850904915889144654">"MIDI کیلئے USB"</string>
@@ -1060,11 +1061,10 @@
<string name="share_remote_bugreport_action" msgid="6249476773913384948">"اشتراک کریں"</string>
<string name="decline_remote_bugreport_action" msgid="6230987241608770062">"مسترد کریں"</string>
<string name="select_input_method" msgid="8547250819326693584">"کی بورڈ تبدیل کریں"</string>
- <string name="configure_input_methods" msgid="5673193194563164021">"دیگر کی بورڈز"</string>
<string name="show_ime" msgid="2506087537466597099">"جب فزیکل کی بورڈ فعال ہو تو IME کو اسکرین پر رکھیں"</string>
<string name="hardware" msgid="194658061510127999">"ورچوئل کی بورڈ دکھائیں"</string>
- <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"کی بورڈ کا خاکہ منتخب کریں"</string>
- <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"ایک کی بورڈ کا خاکہ منتخب کرنے کیلئے چھوئیں۔"</string>
+ <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"فزیکل کی بورڈ کنفیگر کریں"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"زبان اور لے آؤٹ منتخب کرنے کیلئے تھپتھپائیں"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"امیدواران"</u></string>
diff --git a/core/res/res/values-uz-rUZ/strings.xml b/core/res/res/values-uz-rUZ/strings.xml
index e3b9e9a..6cb65a3 100644
--- a/core/res/res/values-uz-rUZ/strings.xml
+++ b/core/res/res/values-uz-rUZ/strings.xml
@@ -233,8 +233,8 @@
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Qoidaga muvofiq kontent yashirilgan"</string>
<string name="safeMode" msgid="2788228061547930246">"Xavfsiz usul"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android tizimi"</string>
- <string name="user_owner_label" msgid="2804351898001038951">"Shaxsiy"</string>
- <string name="managed_profile_label" msgid="6260850669674791528">"Ish"</string>
+ <string name="user_owner_label" msgid="1119010402169916617">"Shaxsiy profilga o‘tish"</string>
+ <string name="managed_profile_label" msgid="5289992269827577857">"Ishchi profilga o‘tish"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"Kontaktlar"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"kontaktlarga kirish"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"Joylashuv"</string>
@@ -1045,7 +1045,8 @@
<string name="no_permissions" msgid="7283357728219338112">"Hech qanday ruxsat talab qilinmaydi"</string>
<string name="perm_costs_money" msgid="4902470324142151116">"buning uchun sizdan haq olinishi mumkin"</string>
<string name="dlg_ok" msgid="7376953167039865701">"OK"</string>
- <string name="usb_charging_notification_title" msgid="4004114449249406402">"USB orqali quvvatlash"</string>
+ <string name="usb_charging_notification_title" msgid="6895185153353640787">"USB orqali quvvatlash"</string>
+ <string name="usb_supplying_notification_title" msgid="5310642257296510271">"USB orqali ulangan qurilma quvvatlanmoqda"</string>
<string name="usb_mtp_notification_title" msgid="8396264943589760855">"USB orqali fayl o‘tkazish"</string>
<string name="usb_ptp_notification_title" msgid="1347328437083192112">"USB orqali rasm o‘tkazish"</string>
<string name="usb_midi_notification_title" msgid="4850904915889144654">"USB orqali MIDI"</string>
@@ -1060,11 +1061,10 @@
<string name="share_remote_bugreport_action" msgid="6249476773913384948">"ULASHISH"</string>
<string name="decline_remote_bugreport_action" msgid="6230987241608770062">"RAD ETISH"</string>
<string name="select_input_method" msgid="8547250819326693584">"Klaviaturani o‘zgartirish"</string>
- <string name="configure_input_methods" msgid="5673193194563164021">"Boshqa klaviaturalar"</string>
<string name="show_ime" msgid="2506087537466597099">"Tashqi klaviaturadan foydalanilayotganda buni ekranda saqlab turish"</string>
<string name="hardware" msgid="194658061510127999">"Virtual klaviatura ko‘rsatilsin"</string>
- <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Tugmalar tartibini tanlash"</string>
- <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Tugmalar tartibini tanlash uchun bosing."</string>
+ <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Tashqi klaviaturani sozlash"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Til va sxemani belgilash uchun bosing"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"nomzodlar"</u></string>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index 76743f2..29eef92 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -233,8 +233,8 @@
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Nội dung bị ẩn theo chính sách"</string>
<string name="safeMode" msgid="2788228061547930246">"Chế độ an toàn"</string>
<string name="android_system_label" msgid="6577375335728551336">"Hệ thống Android"</string>
- <string name="user_owner_label" msgid="2804351898001038951">"Cá nhân"</string>
- <string name="managed_profile_label" msgid="6260850669674791528">"Cơ quan"</string>
+ <string name="user_owner_label" msgid="1119010402169916617">"Chuyển sang Cá nhân"</string>
+ <string name="managed_profile_label" msgid="5289992269827577857">"Chuyển sang Công việc"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"Danh bạ"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"truy cập vào danh bạ của bạn"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"Vị trí"</string>
@@ -1045,7 +1045,8 @@
<string name="no_permissions" msgid="7283357728219338112">"Không yêu cầu quyền"</string>
<string name="perm_costs_money" msgid="4902470324142151116">"bạn có thể mất tiền vì điều này"</string>
<string name="dlg_ok" msgid="7376953167039865701">"OK"</string>
- <string name="usb_charging_notification_title" msgid="4004114449249406402">"USB để sạc"</string>
+ <string name="usb_charging_notification_title" msgid="6895185153353640787">"Sạc qua USB thiết bị này"</string>
+ <string name="usb_supplying_notification_title" msgid="5310642257296510271">"Nguồn cấp điện qua USB cho thiết bị được kết nối"</string>
<string name="usb_mtp_notification_title" msgid="8396264943589760855">"USB để truyền tệp"</string>
<string name="usb_ptp_notification_title" msgid="1347328437083192112">"USB để truyền ảnh"</string>
<string name="usb_midi_notification_title" msgid="4850904915889144654">"USB cho MIDI"</string>
@@ -1060,11 +1061,10 @@
<string name="share_remote_bugreport_action" msgid="6249476773913384948">"CHIA SẺ"</string>
<string name="decline_remote_bugreport_action" msgid="6230987241608770062">"TỪ CHỐI"</string>
<string name="select_input_method" msgid="8547250819326693584">"Thay đổi bàn phím"</string>
- <string name="configure_input_methods" msgid="5673193194563164021">"Bàn phím khác"</string>
<string name="show_ime" msgid="2506087537466597099">"Tiếp tục sử dụng ứng dụng trên màn hình trong khi bàn phím thực đang hoạt động"</string>
<string name="hardware" msgid="194658061510127999">"Hiển thị bàn phím ảo"</string>
- <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Chọn bố cục bàn phím"</string>
- <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Chạm để chọn bố cục bàn phím."</string>
+ <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Định cấu hình bàn phím thực"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Nhấn để chọn ngôn ngữ và bố cục"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"ứng viên"</u></string>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index 3b0c075..c216be8 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -233,8 +233,8 @@
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"内容已隐藏(根据政策规定)"</string>
<string name="safeMode" msgid="2788228061547930246">"安全模式"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android 系统"</string>
- <string name="user_owner_label" msgid="2804351898001038951">"个人"</string>
- <string name="managed_profile_label" msgid="6260850669674791528">"工作"</string>
+ <string name="user_owner_label" msgid="1119010402169916617">"切换为“个人”"</string>
+ <string name="managed_profile_label" msgid="5289992269827577857">"切换为“工作”"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"通讯录"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"访问您的通讯录"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"位置信息"</string>
@@ -1045,7 +1045,8 @@
<string name="no_permissions" msgid="7283357728219338112">"不需要任何权限"</string>
<string name="perm_costs_money" msgid="4902470324142151116">"这可能会产生费用"</string>
<string name="dlg_ok" msgid="7376953167039865701">"确定"</string>
- <string name="usb_charging_notification_title" msgid="4004114449249406402">"正在通过 USB 充电"</string>
+ <string name="usb_charging_notification_title" msgid="6895185153353640787">"正在通过 USB 为此设备充电"</string>
+ <string name="usb_supplying_notification_title" msgid="5310642257296510271">"正在通过 USB 为连接的设备充电"</string>
<string name="usb_mtp_notification_title" msgid="8396264943589760855">"正在通过 USB 传输文件"</string>
<string name="usb_ptp_notification_title" msgid="1347328437083192112">"正在通过 USB 传输照片"</string>
<string name="usb_midi_notification_title" msgid="4850904915889144654">"正在通过 USB 连接到 MIDI 接口"</string>
@@ -1060,11 +1061,10 @@
<string name="share_remote_bugreport_action" msgid="6249476773913384948">"分享"</string>
<string name="decline_remote_bugreport_action" msgid="6230987241608770062">"拒绝"</string>
<string name="select_input_method" msgid="8547250819326693584">"更改键盘"</string>
- <string name="configure_input_methods" msgid="5673193194563164021">"其他键盘"</string>
<string name="show_ime" msgid="2506087537466597099">"连接到实体键盘时使其在屏幕上保持显示状态"</string>
<string name="hardware" msgid="194658061510127999">"显示虚拟键盘"</string>
- <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"选择键盘布局"</string>
- <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"触摸可选择键盘布局。"</string>
+ <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"配置实体键盘"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"点按即可选择语言和布局"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"候选"</u></string>
@@ -1224,7 +1224,7 @@
<string name="action_menu_overflow_description" msgid="2295659037509008453">"更多选项"</string>
<string name="action_bar_home_description_format" msgid="7965984360903693903">"%1$s:%2$s"</string>
<string name="action_bar_home_subtitle_description_format" msgid="6985546530471780727">"%1$s - %2$s:%3$s"</string>
- <string name="storage_internal" msgid="3570990907910199483">"内部共享的存储空间"</string>
+ <string name="storage_internal" msgid="3570990907910199483">"内部共享存储空间"</string>
<string name="storage_sd_card" msgid="3282948861378286745">"SD卡"</string>
<string name="storage_sd_card_label" msgid="6347111320774379257">"<xliff:g id="MANUFACTURER">%s</xliff:g> SD 卡"</string>
<string name="storage_usb_drive" msgid="6261899683292244209">"U 盘"</string>
diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml
index e15aaf2..28f2bac 100644
--- a/core/res/res/values-zh-rHK/strings.xml
+++ b/core/res/res/values-zh-rHK/strings.xml
@@ -233,8 +233,8 @@
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"已根據政策隱藏內容"</string>
<string name="safeMode" msgid="2788228061547930246">"安全模式"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android 系統"</string>
- <string name="user_owner_label" msgid="2804351898001038951">"個人"</string>
- <string name="managed_profile_label" msgid="6260850669674791528">"公司"</string>
+ <string name="user_owner_label" msgid="1119010402169916617">"切換至個人設定檔"</string>
+ <string name="managed_profile_label" msgid="5289992269827577857">"切換至工作設定檔"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"通訊錄"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"存取您的通訊錄"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"位置"</string>
@@ -1045,7 +1045,8 @@
<string name="no_permissions" msgid="7283357728219338112">"不需授權"</string>
<string name="perm_costs_money" msgid="4902470324142151116">"這可能需要付費"</string>
<string name="dlg_ok" msgid="7376953167039865701">"確定"</string>
- <string name="usb_charging_notification_title" msgid="4004114449249406402">"USB 充電"</string>
+ <string name="usb_charging_notification_title" msgid="6895185153353640787">"正在透過 USB 為此裝置充電"</string>
+ <string name="usb_supplying_notification_title" msgid="5310642257296510271">"正在透過 USB 為已連接的裝置供電"</string>
<string name="usb_mtp_notification_title" msgid="8396264943589760855">"USB 檔案傳輸"</string>
<string name="usb_ptp_notification_title" msgid="1347328437083192112">"USB 相片傳輸"</string>
<string name="usb_midi_notification_title" msgid="4850904915889144654">"USB MIDI"</string>
@@ -1060,11 +1061,10 @@
<string name="share_remote_bugreport_action" msgid="6249476773913384948">"分享"</string>
<string name="decline_remote_bugreport_action" msgid="6230987241608770062">"拒絕"</string>
<string name="select_input_method" msgid="8547250819326693584">"變更鍵盤"</string>
- <string name="configure_input_methods" msgid="5673193194563164021">"其他鍵盤"</string>
<string name="show_ime" msgid="2506087537466597099">"在實體鍵盤處於連接狀態時保持顯示"</string>
<string name="hardware" msgid="194658061510127999">"顯示虛擬鍵盤"</string>
- <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"選取鍵盤配置"</string>
- <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"輕觸即可選取鍵盤配置。"</string>
+ <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"設定實體鍵盤"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"輕按即可選取語言和鍵盤配置"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"待選項目"</u></string>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index 6e62d1c..dfc7890 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -233,8 +233,8 @@
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"內容已依據政策隱藏"</string>
<string name="safeMode" msgid="2788228061547930246">"安全模式"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android 系統"</string>
- <string name="user_owner_label" msgid="2804351898001038951">"個人"</string>
- <string name="managed_profile_label" msgid="6260850669674791528">"公司"</string>
+ <string name="user_owner_label" msgid="1119010402169916617">"切換至個人設定檔"</string>
+ <string name="managed_profile_label" msgid="5289992269827577857">"切換至公司設定檔"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"聯絡人"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"存取您的聯絡人"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"位置"</string>
@@ -1045,7 +1045,8 @@
<string name="no_permissions" msgid="7283357728219338112">"無須許可"</string>
<string name="perm_costs_money" msgid="4902470324142151116">"這可能需要付費"</string>
<string name="dlg_ok" msgid="7376953167039865701">"確定"</string>
- <string name="usb_charging_notification_title" msgid="4004114449249406402">"正在透過 USB 充電"</string>
+ <string name="usb_charging_notification_title" msgid="6895185153353640787">"正在透過 USB 為這個裝置充電"</string>
+ <string name="usb_supplying_notification_title" msgid="5310642257296510271">"正在透過 USB 為連接的裝置供電"</string>
<string name="usb_mtp_notification_title" msgid="8396264943589760855">"USB 檔案傳輸"</string>
<string name="usb_ptp_notification_title" msgid="1347328437083192112">"USB 相片傳輸"</string>
<string name="usb_midi_notification_title" msgid="4850904915889144654">"USB MIDI"</string>
@@ -1060,11 +1061,10 @@
<string name="share_remote_bugreport_action" msgid="6249476773913384948">"分享"</string>
<string name="decline_remote_bugreport_action" msgid="6230987241608770062">"拒絕"</string>
<string name="select_input_method" msgid="8547250819326693584">"變更鍵盤"</string>
- <string name="configure_input_methods" msgid="5673193194563164021">"其他鍵盤"</string>
<string name="show_ime" msgid="2506087537466597099">"有連接的實體鍵盤時保持顯示"</string>
<string name="hardware" msgid="194658061510127999">"顯示虛擬鍵盤"</string>
- <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"選取鍵盤配置"</string>
- <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"輕觸即可選取鍵盤配置。"</string>
+ <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"設定實體鍵盤"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"輕觸即可選取語言和版面配置"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"待選項目"</u></string>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index ddd486b..e32f26b 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -233,8 +233,8 @@
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Okuqukethwe kufihlwe inqubomgomo"</string>
<string name="safeMode" msgid="2788228061547930246">"Imodi ephephile"</string>
<string name="android_system_label" msgid="6577375335728551336">"Uhlelo lwe-Android"</string>
- <string name="user_owner_label" msgid="2804351898001038951">"Okomuntu siqu"</string>
- <string name="managed_profile_label" msgid="6260850669674791528">"Umsebenzi"</string>
+ <string name="user_owner_label" msgid="1119010402169916617">"Shintshela komuntu siqu"</string>
+ <string name="managed_profile_label" msgid="5289992269827577857">"Shintshela kumsebenzi"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"Oxhumana nabo"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"finyelela koxhumana nabo"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"Indawo"</string>
@@ -1045,7 +1045,8 @@
<string name="no_permissions" msgid="7283357728219338112">"Ayikho imvume edingekayo"</string>
<string name="perm_costs_money" msgid="4902470324142151116">"lokhu kungakudlela imali"</string>
<string name="dlg_ok" msgid="7376953167039865701">"KULUNGILE"</string>
- <string name="usb_charging_notification_title" msgid="4004114449249406402">"I-USB yokushaja"</string>
+ <string name="usb_charging_notification_title" msgid="6895185153353640787">"I-USB ishaja le divayisi"</string>
+ <string name="usb_supplying_notification_title" msgid="5310642257296510271">"I-USB inikeza amandla kudivayisi enamathiselwe"</string>
<string name="usb_mtp_notification_title" msgid="8396264943589760855">"I-USB yokudluliswa kwefayela"</string>
<string name="usb_ptp_notification_title" msgid="1347328437083192112">"I-USB yokudluliswa kwesithombe"</string>
<string name="usb_midi_notification_title" msgid="4850904915889144654">"I-USB ye-MIDI"</string>
@@ -1060,11 +1061,10 @@
<string name="share_remote_bugreport_action" msgid="6249476773913384948">"YABELANA"</string>
<string name="decline_remote_bugreport_action" msgid="6230987241608770062">"YENQABA"</string>
<string name="select_input_method" msgid="8547250819326693584">"Shintsha ikhibhodi"</string>
- <string name="configure_input_methods" msgid="5673193194563164021">"Amanye amakhibhodi"</string>
<string name="show_ime" msgid="2506087537466597099">"Yigcine kusikrini ngenkathi kusebenza ikhibhodi ephathekayo"</string>
<string name="hardware" msgid="194658061510127999">"Bonisa ikhibhodi ebonakalayo"</string>
- <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Khetha isendlalelo sekhibhodi"</string>
- <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Thinta ukuze ukhethe isendlalelo sekhibhodi."</string>
+ <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Lungisa ikhibhodi yoqobo"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Thepha ukuze ukhethe ulimi nesakhiwo"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"abahlanganyeli"</u></string>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index a52c4e5..0ed1f13 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -2846,6 +2846,11 @@
<!-- Pointer icon of a hand sign while grabbing something. -->
<enum name="grabbing" value="1021" />
</attr>
+
+ <!-- Whether this view has elements that may overlap when drawn. See
+ {@link android.view.View#forceHasOverlappingRendering(boolean)}. -->
+ <attr name="forceHasOverlappingRendering" format="boolean" />
+
</declare-styleable>
<!-- Attributes that can be assigned to a tag for a particular View. -->
@@ -3523,6 +3528,13 @@
This setting implies fastScrollEnabled. -->
<attr name="fastScrollAlwaysVisible" format="boolean" />
</declare-styleable>
+ <!-- @hide -->
+ <declare-styleable name="RecycleListView">
+ <!-- Bottom padding to use when no buttons are present. -->
+ <attr name="paddingBottomNoButtons" format="dimension" />
+ <!-- Top padding to use when no title is present. -->
+ <attr name="paddingTopNoTitle" format="dimension" />
+ </declare-styleable>
<declare-styleable name="AbsSpinner">
<!-- Reference to an array resource that will populate the Spinner. For static content,
this is simpler than populating the Spinner programmatically. -->
@@ -4379,8 +4391,7 @@
<attr name="autoLink" />
<!-- If set to false, keeps the movement method from being set
to the link movement method even if autoLink causes links
- to be found or the input text contains a
- {@link android.text.style.ClickableSpan ClickableSpan}. -->
+ to be found. -->
<attr name="linksClickable" format="boolean" />
<!-- If set, specifies that this TextView has a numeric input method.
The default is false.
@@ -7639,6 +7650,12 @@
<!-- Minimum inset for content views within a bar. Navigation buttons and
menu views are excepted. Only valid for some themes and configurations. -->
<attr name="contentInsetRight" format="dimension" />
+ <!-- Minimum inset for content views within a bar when a navigation button
+ is present, such as the Up button. Only valid for some themes and configurations. -->
+ <attr name="contentInsetStartWithNavigation" format="dimension" />
+ <!-- Minimum inset for content views within a bar when actions from a menu
+ are present. Only valid for some themes and configurations. -->
+ <attr name="contentInsetEndWithActions" format="dimension" />
<!-- Elevation for the action bar itself -->
<attr name="elevation" />
<!-- Reference to a theme that should be used to inflate popups
@@ -8006,6 +8023,8 @@
<attr name="contentInsetEnd" />
<attr name="contentInsetLeft" />
<attr name="contentInsetRight" />
+ <attr name="contentInsetStartWithNavigation" />
+ <attr name="contentInsetEndWithActions" />
<attr name="maxButtonHeight" format="dimension" />
<attr name="navigationButtonStyle" format="reference" />
<attr name="buttonGravity">
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index d1c0895..5b4364d 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -225,6 +225,9 @@
granted any application pre-installed on the system image (not just privileged
apps). -->
<flag name="preinstalled" value="0x400" />
+ <!-- Additional flag from base permission type: this permission can be automatically
+ granted to the setup wizard app -->
+ <flag name="setup" value="0x800" />
</attr>
<!-- Flags indicating more context for a permission group. -->
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 6ecaa1f..cae04ad 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -578,6 +578,9 @@
Software implementation will be used if config_hardware_auto_brightness_available is not set -->
<bool name="config_automatic_brightness_available">false</bool>
+ <!-- Fast brightness animation ramp rate -->
+ <integer translatable="false" name="config_brightness_ramp_rate_fast">200</integer>
+
<!-- Don't name config resources like this. It should look like config_annoyDianne -->
<bool name="config_annoy_dianne">true</bool>
@@ -2497,4 +2500,11 @@
<!-- True if the device supports at least one form of multi-window.
E.g. freeform, split-screen, picture-in-picture. -->
<bool name="config_supportsMultiWindow">true</bool>
+
+ <!-- True if the device requires AppWidgetService even if it does not have
+ the PackageManager.FEATURE_APP_WIDGETS feature -->
+ <bool name="config_enableAppWidgetService">false</bool>
+
+ <!-- True if the device supports Sustained Performance Mode-->
+ <bool name="config_sustainedPerformanceModeSupported">false</bool>
</resources>
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index 71d9a1f..a21f276 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -450,6 +450,7 @@
<item type="dimen" format="integer" name="time_picker_column_end_material">1</item>
<item type="dimen" name="aerr_padding_list_top">15dp</item>
+ <item type="dimen" name="aerr_padding_list_bottom">8dp</item>
<item type="fraction" name="docked_stack_divider_fixed_ratio">34.15%</item>
diff --git a/core/res/res/values/dimens_material.xml b/core/res/res/values/dimens_material.xml
index 2fe4f66..00e48a0 100644
--- a/core/res/res/values/dimens_material.xml
+++ b/core/res/res/values/dimens_material.xml
@@ -41,6 +41,8 @@
<dimen name="action_bar_default_padding_end_material">0dp</dimen>
<!-- Default content inset of an action bar. -->
<dimen name="action_bar_content_inset_material">16dp</dimen>
+ <!-- Default content inset of an action bar when a navigation button is present. -->
+ <dimen name="action_bar_content_inset_with_nav">72dp</dimen>
<!-- Vertical padding around action bar icons. -->
<dimen name="action_bar_icon_vertical_padding_material">16dp</dimen>
<!-- Top margin for action bar subtitles -->
@@ -115,13 +117,13 @@
<dimen name="dialog_padding_material">24dp</dimen>
<dimen name="dialog_padding_top_material">18dp</dimen>
+ <dimen name="dialog_title_divider_material">8dp</dimen>
+ <dimen name="dialog_list_padding_top_no_title">8dp</dimen>
+ <dimen name="dialog_list_padding_bottom_no_buttons">8dp</dimen>
<!-- Dialog padding minus control padding, used to fix alignment. -->
<dimen name="select_dialog_padding_start_material">20dp</dimen>
- <!-- Padding above and below selection dialog lists. -->
- <dimen name="dialog_list_padding_vertical_material">8dp</dimen>
-
<dimen name="seekbar_track_background_height_material">2dp</dimen>
<dimen name="seekbar_track_progress_height_material">2dp</dimen>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index ed7b4d8..6ff7139 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2665,7 +2665,6 @@
<public type="attr" name="defaultWidth" />
<public type="attr" name="defaultHeight" />
<public type="attr" name="minimalWidth" />
- <public type="attr" name="minimalHeight" />
<public type="attr" name="resizeableActivity" />
<public type="attr" name="supportsPictureInPicture" />
<public type="attr" name="titleMargin" />
@@ -2710,9 +2709,15 @@
<public type="attr" name="fillType" />
<public type="attr" name="popupEnterTransition" />
<public type="attr" name="popupExitTransition" />
+ <public type="attr" name="minimalHeight" />
+ <public type="attr" name="forceHasOverlappingRendering" />
+ <public type="attr" name="contentInsetStartWithNavigation" />
+ <public type="attr" name="contentInsetEndWithActions" />
<public type="style" name="Theme.Material.Light.DialogWhenLarge.DarkActionBar" />
<public type="style" name="Widget.Material.SeekBar.Discrete" />
+ <public type="style" name="Widget.Material.CompoundButton.Switch" />
+ <public type="style" name="Widget.Material.Light.CompoundButton.Switch" />
<public type="id" name="accessibilityActionSetProgress" />
<public type="id" name="icon_frame" />
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index e94a91d..b4f95dc 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -563,11 +563,11 @@
<!-- Label for the Android system components when they are shown to the user. -->
<string name="android_system_label">Android System</string>
- <!-- Label for the user owner in the intent forwarding app. [CHAR LIMIT=15] -->
- <string name="user_owner_label">Personal</string>
+ <!-- Label for the user owner in the intent forwarding app. -->
+ <string name="user_owner_label">Switch to Personal</string>
- <!-- Label for a corporate profile in the intent forwarding app. [CHAR LIMIT=15] -->
- <string name="managed_profile_label">Work</string>
+ <!-- Label for a corporate profile in the intent forwarding app. -->
+ <string name="managed_profile_label">Switch to Work</string>
<!-- Title of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permgrouplab_contacts">Contacts</string>
@@ -2945,18 +2945,17 @@
<!-- Title of the pop-up dialog in which the user switches keyboard, also known as input method. -->
<string name="select_input_method">Change keyboard</string>
- <!-- Title of a button to open the settings to enable or disable other soft keyboards (also known as input methods) [CHAR LIMIT=30] -->
- <string name="configure_input_methods">Other keyboards</string>
<!-- Summary text of a toggle switch to enable/disable use of the IME while a physical
keyboard is connected -->
<string name="show_ime">Keep it on screen while physical keyboard is active</string>
<!-- Title of the physical keyboard category in the input method selector [CHAR LIMIT=30] -->
<string name="hardware">Show virtual keyboard</string>
- <!-- Title of the notification to prompt the user to select a keyboard layout. -->
- <string name="select_keyboard_layout_notification_title">Select keyboard layout</string>
- <!-- Message of the notification to prompt the user to select a keyboard layout. -->
- <string name="select_keyboard_layout_notification_message">Touch to select a keyboard layout.</string>
+ <!-- Title of the notification to prompt the user to configure physical keyboard settings. -->
+ <string name="select_keyboard_layout_notification_title">Configure physical keyboard</string>
+ <!-- Message of the notification to prompt the user to configure physical keyboard settings
+ where the user can associate language with physical keyboard layout. -->
+ <string name="select_keyboard_layout_notification_message">Tap to select language and layout</string>
<string name="fast_scroll_alphabet">\u0020ABCDEFGHIJKLMNOPQRSTUVWXYZ</string>
<string name="fast_scroll_numeric_alphabet">\u00200123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ</string>
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index 86b9f1d..790dcfa 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -1234,6 +1234,7 @@
<item name="collapseIcon">?attr/homeAsUpIndicator</item>
<item name="collapseContentDescription">@string/toolbar_collapse_description</item>
<item name="contentInsetStart">16dp</item>
+ <item name="contentInsetStartWithNavigation">@dimen/action_bar_content_inset_with_nav</item>
<item name="touchscreenBlocksFocus">true</item>
</style>
diff --git a/core/res/res/values/styles_material.xml b/core/res/res/values/styles_material.xml
index e636bc0..2420c1a 100644
--- a/core/res/res/values/styles_material.xml
+++ b/core/res/res/values/styles_material.xml
@@ -311,7 +311,7 @@
<style name="TextAppearance.Material.Widget.PopupMenu.Header">
<item name="fontFamily">@string/font_family_title_material</item>
<item name="textSize">@dimen/text_size_menu_header_material</item>
- <item name="textColor">?attr/textColorSecondary</item>
+ <item name="textColor">?attr/colorAccent</item>
</style>
<style name="TextAppearance.Material.Widget.DropDownHint" parent="TextAppearance.Material.Menu" />
@@ -944,6 +944,7 @@
<item name="homeLayout">@layout/action_bar_home_material</item>
<item name="gravity">center_vertical</item>
<item name="contentInsetStart">@dimen/action_bar_content_inset_material</item>
+ <item name="contentInsetStartWithNavigation">@dimen/action_bar_content_inset_with_nav</item>
<item name="contentInsetEnd">@dimen/action_bar_content_inset_material</item>
<item name="elevation">@dimen/action_bar_elevation_material</item>
<item name="popupTheme">?attr/actionBarPopupTheme</item>
diff --git a/core/res/res/values/styles_micro.xml b/core/res/res/values/styles_micro.xml
index 7dde5f8..341a0a4 100644
--- a/core/res/res/values/styles_micro.xml
+++ b/core/res/res/values/styles_micro.xml
@@ -17,27 +17,27 @@
<style name="Animation.Micro"/>
<style name="Animation.Micro.Activity" parent="Animation.Material.Activity">
- <item name="activityOpenEnterAnimation">@anim/slide_in_micro</item>
- <item name="activityOpenRemoteViewsEnterAnimation">@anim/slide_in_micro</item>
- <item name="activityOpenExitAnimation">@null</item>
+ <item name="activityOpenEnterAnimation">@anim/slide_in_enter_micro</item>
+ <item name="activityOpenRemoteViewsEnterAnimation">@anim/slide_in_enter_micro</item>
+ <item name="activityOpenExitAnimation">@anim/slide_in_exit_micro</item>
<item name="activityCloseEnterAnimation">@null</item>
<item name="activityCloseExitAnimation">@anim/slide_out_micro</item>
- <item name="taskOpenEnterAnimation">@anim/slide_in_micro</item>
- <item name="taskOpenExitAnimation">@null</item>
+ <item name="taskOpenEnterAnimation">@anim/slide_in_enter_micro</item>
+ <item name="taskOpenExitAnimation">@anim/slide_in_exit_micro</item>
<item name="taskCloseEnterAnimation">@null</item>
<item name="taskCloseExitAnimation">@anim/slide_out_micro</item>
- <item name="taskToFrontEnterAnimation">@anim/slide_in_micro</item>
- <item name="taskToFrontExitAnimation">@null</item>
+ <item name="taskToFrontEnterAnimation">@anim/slide_in_enter_micro</item>
+ <item name="taskToFrontExitAnimation">@anim/slide_in_exit_micro</item>
<item name="taskToBackEnterAnimation">@null</item>
<item name="taskToBackExitAnimation">@anim/slide_out_micro</item>
<item name="wallpaperOpenEnterAnimation">@null</item>
<item name="wallpaperOpenExitAnimation">@anim/slide_out_micro</item>
- <item name="wallpaperCloseEnterAnimation">@anim/slide_in_micro</item>
- <item name="wallpaperCloseExitAnimation">@null</item>
+ <item name="wallpaperCloseEnterAnimation">@anim/slide_in_enter_micro</item>
+ <item name="wallpaperCloseExitAnimation">@anim/slide_in_exit_micro</item>
<item name="wallpaperIntraOpenEnterAnimation">@null</item>
<item name="wallpaperIntraOpenExitAnimation">@anim/slide_out_micro</item>
- <item name="wallpaperIntraCloseEnterAnimation">@anim/slide_in_micro</item>
- <item name="wallpaperIntraCloseExitAnimation">@null</item>
+ <item name="wallpaperIntraCloseEnterAnimation">@anim/slide_in_enter_micro</item>
+ <item name="wallpaperIntraCloseExitAnimation">@anim/slide_in_exit_micro</item>
</style>
<style name="AlertDialog.Micro" parent="AlertDialog.Material.Light">
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 6526571..1e10f86 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -307,6 +307,7 @@
<java-symbol type="bool" name="config_supportsMultiWindow" />
<java-symbol type="bool" name="config_guestUserEphemeral" />
<java-symbol type="bool" name="config_localDisplaysMirrorContent" />
+ <java-symbol type="bool" name="config_enableAppWidgetService" />
<java-symbol type="string" name="config_defaultPictureInPictureBounds" />
<java-symbol type="integer" name="config_wifi_framework_5GHz_preference_boost_threshold" />
<java-symbol type="integer" name="config_wifi_framework_5GHz_preference_boost_factor" />
@@ -1765,6 +1766,7 @@
<java-symbol type="integer" name="config_shutdownBatteryTemperature" />
<java-symbol type="integer" name="config_undockedHdmiRotation" />
<java-symbol type="integer" name="config_virtualKeyQuietTimeMillis" />
+ <java-symbol type="integer" name="config_brightness_ramp_rate_fast" />
<java-symbol type="layout" name="am_compat_mode_dialog" />
<java-symbol type="layout" name="launch_warning" />
<java-symbol type="layout" name="safe_mode" />
@@ -1809,7 +1811,6 @@
<java-symbol type="string" name="config_wimaxServiceClassname" />
<java-symbol type="string" name="config_wimaxServiceJarLocation" />
<java-symbol type="string" name="config_wimaxStateTrackerClassname" />
- <java-symbol type="string" name="configure_input_methods" />
<java-symbol type="string" name="data_usage_3g_limit_snoozed_title" />
<java-symbol type="string" name="data_usage_3g_limit_title" />
<java-symbol type="string" name="data_usage_4g_limit_snoozed_title" />
@@ -2451,24 +2452,6 @@
<java-symbol type="id" name="aerr_close" />
<java-symbol type="id" name="aerr_mute" />
- <!-- Framework-private Material.DayNight styles. -->
- <java-symbol type="style" name="Theme.Material.DayNight" />
- <java-symbol type="style" name="Theme.Material.DayNight.DarkActionBar" />
- <java-symbol type="style" name="Theme.Material.DayNight.Dialog" />
- <java-symbol type="style" name="Theme.Material.DayNight.Dialog.Alert" />
- <java-symbol type="style" name="Theme.Material.DayNight.Dialog.MinWidth" />
- <java-symbol type="style" name="Theme.Material.DayNight.Dialog.NoActionBar" />
- <java-symbol type="style" name="Theme.Material.DayNight.Dialog.NoActionBar.MinWidth" />
- <java-symbol type="style" name="Theme.Material.DayNight.Dialog.Presentation" />
- <java-symbol type="style" name="Theme.Material.DayNight.DialogWhenLarge" />
- <java-symbol type="style" name="Theme.Material.DayNight.DialogWhenLarge.NoActionBar" />
- <java-symbol type="style" name="Theme.Material.DayNight.NoActionBar" />
- <java-symbol type="style" name="Theme.Material.DayNight.NoActionBar.Fullscreen" />
- <java-symbol type="style" name="Theme.Material.DayNight.NoActionBar.Overscan" />
- <java-symbol type="style" name="Theme.Material.DayNight.NoActionBar.TranslucentDecor" />
- <java-symbol type="style" name="Theme.Material.DayNight.Panel" />
- <java-symbol type="style" name="Theme.Material.DayNight.DialogWhenLarge.DarkActionBar" />
-
<java-symbol type="string" name="status_bar_rotate" />
<java-symbol type="string" name="status_bar_headset" />
<java-symbol type="string" name="status_bar_data_saver" />
@@ -2556,4 +2539,9 @@
<!-- WallpaperManager config -->
<java-symbol type="string" name="config_wallpaperCropperPackage" />
+
+ <java-symbol type="id" name="textSpacerNoTitle" />
+ <java-symbol type="id" name="titleDividerNoCustom" />
+
+ <java-symbol type="bool" name="config_sustainedPerformanceModeSupported" />
</resources>
diff --git a/core/res/res/values/themes_material.xml b/core/res/res/values/themes_material.xml
index a361eda..6611eb1 100644
--- a/core/res/res/values/themes_material.xml
+++ b/core/res/res/values/themes_material.xml
@@ -1294,7 +1294,7 @@
</style>
<!-- Default theme for Settings and activities launched from Settings. -->
- <style name="Theme.Material.Settings" parent="Theme.Material.DayNight.DarkActionBar">
+ <style name="Theme.Material.Settings" parent="Theme.Material.Light.DarkActionBar">
<item name="colorPrimary">@color/material_blue_grey_900</item>
<item name="colorPrimaryDark">@color/material_blue_grey_950</item>
@@ -1304,7 +1304,7 @@
</style>
<!-- Default theme for Settings and activities launched from Settings. -->
- <style name="Theme.Material.Settings.NoActionBar" parent="Theme.Material.DayNight.NoActionBar">
+ <style name="Theme.Material.Settings.NoActionBar" parent="Theme.Material.Light.NoActionBar">
<item name="colorPrimary">@color/material_blue_grey_900</item>
<item name="colorPrimaryDark">@color/material_blue_grey_950</item>
@@ -1313,41 +1313,41 @@
<item name="panelMenuListTheme">@style/Theme.Material.Settings.CompactMenu</item>
</style>
- <style name="Theme.Material.Settings.BaseDialog" parent="Theme.Material.DayNight.BaseDialog">
+ <style name="Theme.Material.Settings.BaseDialog" parent="Theme.Material.Light.BaseDialog">
<item name="colorPrimary">@color/material_blue_grey_900</item>
<item name="colorPrimaryDark">@color/material_blue_grey_950</item>
</style>
<style name="Theme.Material.Settings.Dialog" parent="Theme.Material.Settings.BaseDialog" />
- <style name="Theme.Material.Settings.Dialog.BaseAlert" parent="Theme.Material.DayNight.Dialog.BaseAlert">
+ <style name="Theme.Material.Settings.Dialog.BaseAlert" parent="Theme.Material.Light.Dialog.BaseAlert">
<item name="colorPrimary">@color/material_blue_grey_900</item>
<item name="colorPrimaryDark">@color/material_blue_grey_950</item>
</style>
<style name="Theme.Material.Settings.Dialog.Alert" parent="Theme.Material.Settings.Dialog.BaseAlert" />
- <style name="Theme.Material.Settings.DialogWhenLarge" parent="Theme.Material.DayNight.DialogWhenLarge.DarkActionBar">
+ <style name="Theme.Material.Settings.DialogWhenLarge" parent="Theme.Material.Light.DialogWhenLarge.DarkActionBar">
<item name="colorPrimary">@color/material_blue_grey_900</item>
<item name="colorPrimaryDark">@color/material_blue_grey_950</item>
</style>
- <style name="Theme.Material.Settings.DialogWhenLarge.NoActionBar" parent="Theme.Material.DayNight.DialogWhenLarge.NoActionBar">
+ <style name="Theme.Material.Settings.DialogWhenLarge.NoActionBar" parent="Theme.Material.Light.DialogWhenLarge.NoActionBar">
<item name="colorPrimary">@color/material_blue_grey_900</item>
<item name="colorPrimaryDark">@color/material_blue_grey_950</item>
</style>
- <style name="Theme.Material.Settings.Dialog.Presentation" parent="Theme.Material.DayNight.Dialog.Presentation">
+ <style name="Theme.Material.Settings.Dialog.Presentation" parent="Theme.Material.Light.Dialog.Presentation">
<item name="colorPrimary">@color/material_blue_grey_900</item>
<item name="colorPrimaryDark">@color/material_blue_grey_950</item>
</style>
- <style name="Theme.Material.Settings.SearchBar" parent="Theme.Material.DayNight.SearchBar">
+ <style name="Theme.Material.Settings.SearchBar" parent="Theme.Material.Light.SearchBar">
<item name="colorPrimary">@color/material_blue_grey_900</item>
<item name="colorPrimaryDark">@color/material_blue_grey_950</item>
</style>
- <style name="Theme.Material.Settings.CompactMenu" parent="Theme.Material.DayNight.CompactMenu">
+ <style name="Theme.Material.Settings.CompactMenu" parent="Theme.Material.Light.CompactMenu">
<item name="colorPrimary">@color/material_blue_grey_900</item>
<item name="colorPrimaryDark">@color/material_blue_grey_950</item>
</style>
diff --git a/core/res/res/values/themes_material_daynight.xml b/core/res/res/values/themes_material_daynight.xml
deleted file mode 100644
index 4ecca6b..0000000
--- a/core/res/res/values/themes_material_daynight.xml
+++ /dev/null
@@ -1,117 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2015 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-
-<!--
-===============================================================
- PLEASE READ
-===============================================================
-
-The Material themes must not be modified in order to pass CTS.
-Many related themes and styles depend on other values defined in this file.
-If you would like to provide custom themes and styles for your device,
-please see themes_device_defaults.xml.
-
-===============================================================
- PLEASE READ
-===============================================================
- -->
-<resources>
-
- <!-- Material theme (day/night vesion) for activities. -->
- <style name="Theme.Material.DayNight" parent="Theme.Material.Light" />
-
- <!-- Variant of Material.DayNight that has a solid (opaque) action bar
- with an inverse color profile. The dark action bar sharply stands out against
- the light content (when applicable). -->
- <style name="Theme.Material.DayNight.DarkActionBar" parent="Theme.Material.Light.DarkActionBar" />
-
- <!-- Variant of Material.DayNight with no action bar. -->
- <style name="Theme.Material.DayNight.NoActionBar" parent="Theme.Material.Light.NoActionBar" />
-
- <!-- Variant of Material.DayNight that has no title bar and fills
- the entire screen. This theme
- sets {@link android.R.attr#windowFullscreen} to true. -->
- <style name="Theme.Material.DayNight.NoActionBar.Fullscreen" parent="Theme.Material.Light.NoActionBar.Fullscreen" />
-
- <!-- Variant of Material.DayNight that has no title bar and fills
- the entire screen and extends into the display overscan region. This theme
- sets {@link android.R.attr#windowFullscreen} and {@link android.R.attr#windowOverscan}
- to true. -->
- <style name="Theme.Material.DayNight.NoActionBar.Overscan" parent="Theme.Material.Light.NoActionBar.Overscan" />
-
- <!-- Variant of Material.DayNight that has no title bar and translucent
- system decor. This theme sets {@link android.R.attr#windowTranslucentStatus} and
- {@link android.R.attr#windowTranslucentNavigation} to true. -->
- <style name="Theme.Material.DayNight.NoActionBar.TranslucentDecor" parent="Theme.Material.Light.NoActionBar.TranslucentDecor" />
-
- <!-- Default Material.DayNight theme for panel windows. This removes all extraneous
- window decorations, so you basically have an empty rectangle in which
- to place your content. It makes the window floating, with a transparent
- background, and turns off dimming behind the window. -->
- <style name="Theme.Material.DayNight.Panel" parent="Theme.Material.Light.Panel" />
-
- <!-- Material theme (day/night vesion) for dialog windows and activities,
- which is used by the {@link android.app.Dialog} class. This changes
- the window to be floating (not fill the entire screen), and puts a
- frame around its contents. You can set this theme on an activity if
- you would like to make an activity that looks like a Dialog. -->
- <style name="Theme.Material.DayNight.Dialog" parent="Theme.Material.DayNight.BaseDialog" />
- <style name="Theme.Material.DayNight.BaseDialog" parent="Theme.Material.Light.BaseDialog" />
-
- <!-- Variant of Theme.Material.DayNight.Dialog that has a nice minimum width for
- a regular dialog. -->
- <style name="Theme.Material.DayNight.Dialog.MinWidth" parent="Theme.Material.Light.Dialog.MinWidth" />
-
- <!-- Variant of Theme.Material.DayNight.Dialog that does not include a title bar. -->
- <style name="Theme.Material.DayNight.Dialog.NoActionBar" parent="Theme.Material.Light.Dialog.NoActionBar" />
-
- <!-- Variant of Theme.Material.DayNight.Dialog.NoActionBar that has a nice minimum width for
- a regular dialog. -->
- <style name="Theme.Material.DayNight.Dialog.NoActionBar.MinWidth" parent="Theme.Material.Light.Dialog.NoActionBar.MinWidth" />
-
- <!-- Variant of Theme.Material.DayNight.Dialog that has a fixed size. -->
- <style name="Theme.Material.DayNight.Dialog.FixedSize" parent="Theme.Material.Light.Dialog.FixedSize" />
-
- <!-- Variant of Theme.Material.DayNight.Dialog.NoActionBar that has a fixed size. -->
- <style name="Theme.Material.DayNight.Dialog.NoActionBar.FixedSize" parent="Theme.Material.Light.Dialog.NoActionBar.FixedSize" />
-
- <!-- Theme for a window that will be displayed either full-screen on
- smaller screens (small, normal) or as a dialog on larger screens
- (large, xlarge). -->
- <style name="Theme.Material.DayNight.DialogWhenLarge" parent="Theme.Material.Light.DialogWhenLarge" />
-
- <!-- Theme for a window with a dark action bar that will be displayed
- either full-screen on smaller screens (small, normal) or as a dialog
- on larger screens (large, xlarge). -->
- <style name="Theme.Material.DayNight.DialogWhenLarge.DarkActionBar" parent="Theme.Material.Light.DialogWhenLarge.DarkActionBar" />
-
- <!-- Theme for a window without an action bar that will be displayed either full-screen
- on smaller screens (small, normal) or as a dialog on larger screens
- (large, xlarge). -->
- <style name="Theme.Material.DayNight.DialogWhenLarge.NoActionBar" parent="Theme.Material.Light.DialogWhenLarge.NoActionBar" />
-
- <!-- Theme for a presentation window on a secondary display. -->
- <style name="Theme.Material.DayNight.Dialog.Presentation" parent="Theme.Material.Light.Dialog.Presentation" />
-
- <!-- Material user theme for alert dialog windows, which is used by the
- {@link android.app.AlertDialog} class. -->
- <style name="Theme.Material.DayNight.Dialog.Alert" parent="Theme.Material.DayNight.Dialog.BaseAlert" />
- <style name="Theme.Material.DayNight.Dialog.BaseAlert" parent="Theme.Material.Light.Dialog.BaseAlert" />
-
- <style name="Theme.Material.DayNight.SearchBar" parent="Theme.Material.Light.SearchBar" />
- <style name="Theme.Material.DayNight.CompactMenu" parent="Theme.Material.Light.CompactMenu" />
-
-</resources>
diff --git a/core/res/res/xml/power_profile.xml b/core/res/res/xml/power_profile.xml
index 76b5fe1..2e593a3 100644
--- a/core/res/res/xml/power_profile.xml
+++ b/core/res/res/xml/power_profile.xml
@@ -94,11 +94,27 @@
<!-- This is the battery capacity in mAh (measured at nominal voltage) -->
<item name="battery.capacity">1000</item>
- <array name="wifi.batchedscan"> <!-- mA -->
- <value>.0002</value> <!-- 1-8/hr -->
- <value>.002</value> <!-- 9-64/hr -->
- <value>.02</value> <!-- 65-512/hr -->
- <value>.2</value> <!-- 513-4,096/hr -->
- <value>2</value> <!-- 4097-/hr -->
+ <!-- Wifi related values. -->
+ <!-- Idle Receive current for wifi radio in mA. 0 by default-->
+ <item name="wifi.controller.idle">0</item>
+ <!-- Rx current for wifi radio in mA. 0 by default-->
+ <item name="wifi.controller.rx">0</item>
+ <!-- Tx current for wifi radio in mA. 0 by default-->
+ <item name="wifi.controller.tx">0</item>
+ <!-- Current at each of the wifi Tx levels in mA. The number of tx levels varies per device
+ and is available only of wifi chipsets which support the tx level reporting. Use
+ wifi.tx for other chipsets. none by default -->
+ <array name="wifi.controller.tx_levels"> <!-- mA -->
</array>
+ <!-- Operating volatage for wifi radio in mV. 0 by default-->
+ <item name="wifi.controller.voltage">0</item>
+
+ <array name="wifi.batchedscan"> <!-- mA -->
+ <value>.0002</value> <!-- 1-8/hr -->
+ <value>.002</value> <!-- 9-64/hr -->
+ <value>.02</value> <!-- 65-512/hr -->
+ <value>.2</value> <!-- 513-4,096/hr -->
+ <value>2</value> <!-- 4097-/hr -->
+ </array>
+
</device>
diff --git a/core/tests/benchmarks/src/android/text/util/LinkifyBenchmark.java b/core/tests/benchmarks/src/android/text/util/LinkifyBenchmark.java
new file mode 100644
index 0000000..a6e433f
--- /dev/null
+++ b/core/tests/benchmarks/src/android/text/util/LinkifyBenchmark.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.text.util;
+
+import com.google.caliper.AfterExperiment;
+import com.google.caliper.BeforeExperiment;
+import com.google.caliper.Benchmark;
+import com.google.caliper.Param;
+
+import android.text.Spannable;
+import android.text.SpannableString;
+import android.util.Patterns;
+
+import java.util.regex.Pattern;
+
+public class LinkifyBenchmark {
+ private static final String MATCHING_STR = " http://user:pass@host.com:5432/path?k=v#f " +
+ "host.com:5432/path?k=v#f ";
+
+ private static final String NONMATCHING_STR = " Neque porro quisquam est qui dolorem ipsum " +
+ "quia dolor sit amet, consectetur, adipisci velit ";
+
+ // this pattern does not recognize strings without http scheme therefore is expected to be
+ // faster in MATCHING_STR case.
+ private static final Pattern BASIC_PATTERN = Pattern.compile(
+ "(?:\\b|$|^)http://[a-zA-Z0-9:\\.@\\?=#/]+(?:\\b|$|^)");
+
+ @Param({"1", "4", "16", "64", "256"})
+ private String mParamCopyAmount;
+
+ @Param({MATCHING_STR, NONMATCHING_STR})
+ private String mParamBasicText;
+
+ private Spannable mTestSpannable;
+
+ @BeforeExperiment
+ protected void setUp() throws Exception {
+ int copyAmount = Integer.valueOf(mParamCopyAmount);
+ StringBuilder strBuilder = new StringBuilder();
+ for (int i = 0; i < copyAmount; i++) {
+ strBuilder.append(mParamBasicText);
+ }
+ mTestSpannable = new SpannableString(strBuilder.toString());
+ }
+
+ @AfterExperiment
+ protected void tearDown() {
+ mTestSpannable = null;
+ }
+
+ @Benchmark
+ public void timeNewRegEx(int reps) throws Exception {
+ for (int i = 0; i < reps; i++) {
+ Linkify.addLinks(mTestSpannable, Patterns.AUTOLINK_WEB_URL, "http://",
+ new String[]{"http://", "https://", "rtsp://"}, null, null);
+ }
+ }
+
+ @Benchmark
+ public void timeOldRegEx(int reps) throws Exception {
+ for (int i = 0; i < reps; i++) {
+ Linkify.addLinks(mTestSpannable, Patterns.WEB_URL, "http://",
+ new String[]{"http://", "https://", "rtsp://"}, null, null);
+ }
+ }
+
+ @Benchmark
+ public void timeBasicRegEx(int reps) throws Exception {
+ for (int i = 0; i < reps; i++) {
+ Linkify.addLinks(mTestSpannable, BASIC_PATTERN, "http://",
+ new String[]{"http://", "https://", "rtsp://"}, null, null);
+ }
+ }
+
+}
diff --git a/core/tests/coretests/AndroidManifest.xml b/core/tests/coretests/AndroidManifest.xml
index b780778..b7926cf 100644
--- a/core/tests/coretests/AndroidManifest.xml
+++ b/core/tests/coretests/AndroidManifest.xml
@@ -1093,7 +1093,12 @@
</intent-filter>
</activity>
-
+ <activity android:name="android.view.ViewCaptureTestActivity" android:label="ViewCaptureTestActivity">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+ </intent-filter>
+ </activity>
<!-- Activity-level metadata -->
<meta-data android:name="com.android.frameworks.coretests.isApp" android:value="true" />
@@ -1251,6 +1256,15 @@
<service android:name="android.os.BinderThreadPriorityService"
android:process=":BinderThreadPriorityService" />
+ <!-- Used by ApplyOverrideConfigurationTest -->
+ <activity android:name="android.app.activity.ApplyOverrideConfigurationActivity"
+ android:configChanges="orientation|screenSize">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+ </intent-filter>
+ </activity>
+
<!-- Application components used for search manager tests -->
<activity android:name="android.app.activity.SearchableActivity"
diff --git a/core/tests/coretests/res/drawable-nodpi/view_capture_test_no_children_golden.png b/core/tests/coretests/res/drawable-nodpi/view_capture_test_no_children_golden.png
new file mode 100644
index 0000000..52092c4
--- /dev/null
+++ b/core/tests/coretests/res/drawable-nodpi/view_capture_test_no_children_golden.png
Binary files differ
diff --git a/core/tests/coretests/res/drawable-nodpi/view_capture_test_with_children_golden.png b/core/tests/coretests/res/drawable-nodpi/view_capture_test_with_children_golden.png
new file mode 100644
index 0000000..3bcbd9a
--- /dev/null
+++ b/core/tests/coretests/res/drawable-nodpi/view_capture_test_with_children_golden.png
Binary files differ
diff --git a/core/tests/coretests/res/layout/view_capture_snapshot.xml b/core/tests/coretests/res/layout/view_capture_snapshot.xml
new file mode 100644
index 0000000..0b589a4
--- /dev/null
+++ b/core/tests/coretests/res/layout/view_capture_snapshot.xml
@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2016, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <LinearLayout android:id="@+id/capture"
+ android:background="#00f"
+ android:orientation="vertical"
+ android:layout_width="100px"
+ android:layout_height="100px">
+
+ <View android:id="@+id/child1"
+ android:background="#f00"
+ android:layout_width="match_parent"
+ android:layout_height="25px"/>
+
+ <View android:id="@+id/child2"
+ android:background="#fff"
+ android:layout_width="match_parent"
+ android:layout_height="25px"
+ android:visibility="invisible"/>
+
+ <View android:id="@+id/child3"
+ android:background="#ff0"
+ android:layout_width="match_parent"
+ android:layout_height="25px"
+ android:visibility="gone"/>
+
+ <View android:id="@+id/child4"
+ android:background="#0ff"
+ android:layout_width="match_parent"
+ android:layout_height="25px" />
+ </LinearLayout>
+</FrameLayout>
diff --git a/core/tests/coretests/src/android/app/DownloadManagerFunctionalTest.java b/core/tests/coretests/src/android/app/DownloadManagerFunctionalTest.java
index 4a53852..d1a5d28 100644
--- a/core/tests/coretests/src/android/app/DownloadManagerFunctionalTest.java
+++ b/core/tests/coretests/src/android/app/DownloadManagerFunctionalTest.java
@@ -284,20 +284,30 @@
Uri uri = getServerUri(DEFAULT_FILENAME);
enqueueResponse(buildResponse(HTTP_PARTIAL_CONTENT));
- doErrorTest(uri, DownloadManager.ERROR_UNHANDLED_HTTP_CODE);
+ doErrorTest(uri, DownloadManager.ERROR_CANNOT_RESUME);
}
/**
* Tests the download failure error from an unhandled HTTP status code
*/
@LargeTest
- public void testErrorHttpDataError_invalidRedirect() throws Exception {
+ public void testRelativeRedirect() throws Exception {
Uri uri = getServerUri(DEFAULT_FILENAME);
final MockResponse resp = buildResponse(HTTP_REDIRECT);
- resp.setHeader("Location", "://blah.blah.blah.com");
+ resp.setHeader("Location", ":" + uri.getSchemeSpecificPart());
enqueueResponse(resp);
- doErrorTest(uri, DownloadManager.ERROR_HTTP_DATA_ERROR);
+ byte[] blobData = generateData(DEFAULT_FILE_SIZE, DataType.TEXT);
+ enqueueResponse(buildResponse(HTTP_OK, blobData));
+
+ Request request = new Request(uri);
+ request.setTitle(DEFAULT_FILENAME);
+
+ long dlRequest = mDownloadManager.enqueue(request);
+ waitForDownloadOrTimeout(dlRequest);
+
+ verifyAndCleanupSingleFileDownload(dlRequest, blobData);
+ assertEquals(1, mReceiver.numDownloadsCompleted());
}
/**
diff --git a/core/tests/coretests/src/android/app/activity/ApplyOverrideConfigurationActivity.java b/core/tests/coretests/src/android/app/activity/ApplyOverrideConfigurationActivity.java
new file mode 100644
index 0000000..3df522d
--- /dev/null
+++ b/core/tests/coretests/src/android/app/activity/ApplyOverrideConfigurationActivity.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package android.app.activity;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.res.Configuration;
+
+public class ApplyOverrideConfigurationActivity extends Activity {
+
+ @Override
+ protected void attachBaseContext(Context newBase) {
+ super.attachBaseContext(newBase);
+
+ Configuration overrideConfig = new Configuration();
+ overrideConfig.smallestScreenWidthDp = ApplyOverrideConfigurationTest.OVERRIDE_WIDTH;
+ applyOverrideConfiguration(overrideConfig);
+ }
+}
diff --git a/core/tests/coretests/src/android/app/activity/ApplyOverrideConfigurationTest.java b/core/tests/coretests/src/android/app/activity/ApplyOverrideConfigurationTest.java
new file mode 100644
index 0000000..15ed77e
--- /dev/null
+++ b/core/tests/coretests/src/android/app/activity/ApplyOverrideConfigurationTest.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package android.app.activity;
+
+import android.app.UiAutomation;
+import android.content.res.Configuration;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.test.ActivityInstrumentationTestCase2;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class ApplyOverrideConfigurationTest extends
+ ActivityInstrumentationTestCase2<ApplyOverrideConfigurationActivity> {
+
+ public static final int OVERRIDE_WIDTH = 9999;
+
+ public ApplyOverrideConfigurationTest() {
+ super(ApplyOverrideConfigurationActivity.class);
+ }
+
+ @Before
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+ injectInstrumentation(InstrumentationRegistry.getInstrumentation());
+ getInstrumentation().getUiAutomation().setRotation(UiAutomation.ROTATION_FREEZE_0);
+ }
+
+ @Test
+ public void testConfigurationIsOverriden() throws Exception {
+ Configuration config = getActivity().getResources().getConfiguration();
+ assertEquals(OVERRIDE_WIDTH, config.smallestScreenWidthDp);
+
+ getInstrumentation().getUiAutomation().setRotation(UiAutomation.ROTATION_FREEZE_90);
+
+ config = getActivity().getResources().getConfiguration();
+ assertEquals(OVERRIDE_WIDTH, config.smallestScreenWidthDp);
+ }
+
+ @After
+ @Override
+ public void tearDown() throws Exception {
+ getInstrumentation().getUiAutomation().setRotation(UiAutomation.ROTATION_UNFREEZE);
+ super.tearDown();
+ }
+}
diff --git a/core/tests/coretests/src/android/content/res/ResourcesManagerTest.java b/core/tests/coretests/src/android/content/res/ResourcesManagerTest.java
index 3cadbf6..d4bb0f3 100644
--- a/core/tests/coretests/src/android/content/res/ResourcesManagerTest.java
+++ b/core/tests/coretests/src/android/content/res/ResourcesManagerTest.java
@@ -18,7 +18,7 @@
import android.annotation.NonNull;
import android.app.ResourcesManager;
import android.os.Binder;
-import android.test.suitebuilder.annotation.SmallTest;
+import android.support.test.filters.SmallTest;
import android.util.DisplayMetrics;
import android.util.LocaleList;
import android.util.TypedValue;
@@ -58,7 +58,7 @@
}
@Override
- protected DisplayMetrics getDisplayMetricsLocked(int displayId) {
+ protected DisplayMetrics getDisplayMetrics(int displayId) {
return mDisplayMetrics;
}
};
@@ -173,25 +173,12 @@
// The implementations should be the same.
assertSame(resources1.getImpl(), resources2.getImpl());
-
- final Configuration overrideConfig = new Configuration();
- overrideConfig.orientation = Configuration.ORIENTATION_LANDSCAPE;
- Resources resources3 = mResourcesManager.getResources(
- activity2, APP_ONE_RES_DIR, null, null, null, Display.DEFAULT_DISPLAY,
- overrideConfig, CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null);
-
- // Since we requested new resources for activity2, the resource should be the same
- // as the one returned before for activity2.
- assertSame(resources2, resources3);
-
- // But the implementation has changed.
- assertNotSame(resources1.getImpl(), resources2.getImpl());
}
@SmallTest
public void testThemesGetUpdatedWithNewImpl() {
Binder activity1 = new Binder();
- Resources resources1 = mResourcesManager.getResources(
+ Resources resources1 = mResourcesManager.createBaseActivityResources(
activity1, APP_ONE_RES_DIR, null, null, null, Display.DEFAULT_DISPLAY, null,
CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null);
assertNotNull(resources1);
@@ -207,16 +194,59 @@
final Configuration overrideConfig = new Configuration();
overrideConfig.orientation = Configuration.ORIENTATION_LANDSCAPE;
- Resources resources2 = mResourcesManager.getResources(
- activity1, APP_ONE_RES_DIR, null, null, null, Display.DEFAULT_DISPLAY,
- overrideConfig, CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null);
- assertNotNull(resources2);
- assertSame(resources1, resources2);
- assertSame(resources2, theme.getResources());
+ mResourcesManager.updateResourcesForActivity(activity1, overrideConfig);
+ assertSame(resources1, theme.getResources());
// Make sure we can still access the data.
assertTrue(theme.resolveAttribute(android.R.attr.windowNoTitle, value, true));
assertEquals(TypedValue.TYPE_INT_BOOLEAN, value.type);
assertTrue(value.data != 0);
}
+
+ @SmallTest
+ public void testMultipleResourcesForOneActivityGetUpdatedWhenActivityBaseUpdates() {
+ Binder activity1 = new Binder();
+
+ // Create a Resources for the Activity.
+ Configuration config1 = new Configuration();
+ config1.densityDpi = 280;
+ Resources resources1 = mResourcesManager.createBaseActivityResources(
+ activity1, APP_ONE_RES_DIR, null, null, null, Display.DEFAULT_DISPLAY, config1,
+ CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null);
+ assertNotNull(resources1);
+
+ // Create a Resources based on the Activity.
+ Configuration config2 = new Configuration();
+ config2.screenLayout |= Configuration.SCREENLAYOUT_ROUND_YES;
+ Resources resources2 = mResourcesManager.getResources(
+ activity1, APP_ONE_RES_DIR, null, null, null, Display.DEFAULT_DISPLAY, config2,
+ CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null);
+ assertNotNull(resources2);
+
+ assertNotSame(resources1, resources2);
+ assertNotSame(resources1.getImpl(), resources2.getImpl());
+
+ final Configuration expectedConfig1 = new Configuration();
+ expectedConfig1.setLocales(LocaleList.getAdjustedDefault());
+ expectedConfig1.densityDpi = 280;
+ assertEquals(expectedConfig1, resources1.getConfiguration());
+
+ // resources2 should be based on the Activity's override config, so the density should
+ // be the same as resources1.
+ final Configuration expectedConfig2 = new Configuration();
+ expectedConfig2.setLocales(LocaleList.getAdjustedDefault());
+ expectedConfig2.densityDpi = 280;
+ expectedConfig2.screenLayout |= Configuration.SCREENLAYOUT_ROUND_YES;
+ assertEquals(expectedConfig2, resources2.getConfiguration());
+
+ // Now update the Activity base override, and both resources should update.
+ config1.orientation = Configuration.ORIENTATION_LANDSCAPE;
+ mResourcesManager.updateResourcesForActivity(activity1, config1);
+
+ expectedConfig1.orientation = Configuration.ORIENTATION_LANDSCAPE;
+ assertEquals(expectedConfig1, resources1.getConfiguration());
+
+ expectedConfig2.orientation = Configuration.ORIENTATION_LANDSCAPE;
+ assertEquals(expectedConfig2, resources2.getConfiguration());
+ }
}
diff --git a/core/tests/coretests/src/android/print/BasePrintTest.java b/core/tests/coretests/src/android/print/BasePrintTest.java
index c9bc8aa..d56a405 100644
--- a/core/tests/coretests/src/android/print/BasePrintTest.java
+++ b/core/tests/coretests/src/android/print/BasePrintTest.java
@@ -28,6 +28,7 @@
import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.content.res.Resources;
+import android.os.CancellationSignal;
import android.os.ParcelFileDescriptor;
import android.os.SystemClock;
import android.print.PrintAttributes;
@@ -281,7 +282,8 @@
}
if (onRequestCustomPrinterIcon != null) {
doAnswer(onRequestCustomPrinterIcon).when(callbacks).onRequestCustomPrinterIcon(
- any(PrinterId.class), any(CustomPrinterIconCallback.class));
+ any(PrinterId.class), any(CancellationSignal.class),
+ any(CustomPrinterIconCallback.class));
}
if (onStopPrinterStateTracking != null) {
doAnswer(onStopPrinterStateTracking).when(callbacks).onStopPrinterStateTracking(
diff --git a/core/tests/coretests/src/android/print/IPrintManagerParametersTest.java b/core/tests/coretests/src/android/print/IPrintManagerParametersTest.java
index ec8cd71..43a61e3 100644
--- a/core/tests/coretests/src/android/print/IPrintManagerParametersTest.java
+++ b/core/tests/coretests/src/android/print/IPrintManagerParametersTest.java
@@ -31,6 +31,7 @@
import android.print.PrintAttributes.MediaSize;
import android.print.PrintAttributes.Resolution;
import android.printservice.PrintServiceInfo;
+import android.printservice.recommendation.IRecommendationsChangeListener;
import android.print.mockservice.MockPrintService;
import android.print.mockservice.PrintServiceCallbacks;
@@ -181,6 +182,17 @@
new Handler(Looper.getMainLooper()));
}
+ /**
+ * Create a IPrintServiceRecommendationsChangeListener object.
+ *
+ * @return the object
+ * @throws Exception if the object could not be created.
+ */
+ private IRecommendationsChangeListener
+ createMockIPrintServiceRecommendationsChangeListener() throws Exception {
+ return new PrintManager.PrintServiceRecommendationsChangeListenerWrapper(null,
+ new Handler(Looper.getMainLooper()));
+ }
/**
* Create a IPrinterDiscoveryObserver object.
@@ -559,6 +571,61 @@
}
/**
+ * test IPrintManager.addPrintServiceRecommendationsChangeListener
+ */
+ @MediumTest
+ public void testAddPrintServiceRecommendationsChangeListener() throws Exception {
+ final IRecommendationsChangeListener listener =
+ createMockIPrintServiceRecommendationsChangeListener();
+
+ mIPrintManager.addPrintServiceRecommendationsChangeListener(listener, mUserId);
+
+ assertException(new Invokable() {
+ @Override
+ public void run() throws Exception {
+ mIPrintManager.addPrintServiceRecommendationsChangeListener(null, mUserId);
+ }
+ }, NullPointerException.class);
+
+ // Cannot test bad user Id as these tests are allowed to call across users
+ }
+
+ /**
+ * test IPrintManager.removePrintServicesChangeListener
+ */
+ @MediumTest
+ public void testRemovePrintServiceRecommendationsChangeListener() throws Exception {
+ final IRecommendationsChangeListener listener =
+ createMockIPrintServiceRecommendationsChangeListener();
+
+ mIPrintManager.addPrintServiceRecommendationsChangeListener(listener, mUserId);
+ mIPrintManager.removePrintServiceRecommendationsChangeListener(listener, mUserId);
+
+ // Removing unknown listeners is a no-op
+ mIPrintManager.removePrintServiceRecommendationsChangeListener(listener, mUserId);
+
+ mIPrintManager.addPrintServiceRecommendationsChangeListener(listener, mUserId);
+ assertException(new Invokable() {
+ @Override
+ public void run() throws Exception {
+ mIPrintManager.removePrintServiceRecommendationsChangeListener(null, mUserId);
+ }
+ }, NullPointerException.class);
+
+ // Cannot test bad user Id as these tests are allowed to call across users
+ }
+
+ /**
+ * test IPrintManager.getPrintServiceRecommendations
+ */
+ @MediumTest
+ public void testGetPrintServiceRecommendations() throws Exception {
+ mIPrintManager.getPrintServiceRecommendations(mUserId);
+
+ // Cannot test bad user Id as these tests are allowed to call across users
+ }
+
+ /**
* test IPrintManager.createPrinterDiscoverySession
*/
@MediumTest
diff --git a/core/tests/coretests/src/android/print/mockservice/PrinterDiscoverySessionCallbacks.java b/core/tests/coretests/src/android/print/mockservice/PrinterDiscoverySessionCallbacks.java
index 26b7cae..be002e2 100644
--- a/core/tests/coretests/src/android/print/mockservice/PrinterDiscoverySessionCallbacks.java
+++ b/core/tests/coretests/src/android/print/mockservice/PrinterDiscoverySessionCallbacks.java
@@ -16,6 +16,7 @@
package android.print.mockservice;
+import android.os.CancellationSignal;
import android.print.PrinterId;
import android.printservice.CustomPrinterIconCallback;
@@ -42,7 +43,7 @@
public abstract void onStartPrinterStateTracking(PrinterId printerId);
public abstract void onRequestCustomPrinterIcon(PrinterId printerId,
- CustomPrinterIconCallback callback);
+ CancellationSignal cancellationSignal, CustomPrinterIconCallback callback);
public abstract void onStopPrinterStateTracking(PrinterId printerId);
diff --git a/core/tests/coretests/src/android/print/mockservice/StubbablePrinterDiscoverySession.java b/core/tests/coretests/src/android/print/mockservice/StubbablePrinterDiscoverySession.java
index 04683f2..e132d79 100644
--- a/core/tests/coretests/src/android/print/mockservice/StubbablePrinterDiscoverySession.java
+++ b/core/tests/coretests/src/android/print/mockservice/StubbablePrinterDiscoverySession.java
@@ -16,6 +16,7 @@
package android.print.mockservice;
+import android.os.CancellationSignal;
import android.print.PrinterId;
import android.printservice.CustomPrinterIconCallback;
import android.printservice.PrintService;
@@ -70,9 +71,9 @@
@Override
public void onRequestCustomPrinterIcon(PrinterId printerId,
- CustomPrinterIconCallback callback) {
+ CancellationSignal cancellationSignal, CustomPrinterIconCallback callback) {
if (mCallbacks != null) {
- mCallbacks.onRequestCustomPrinterIcon(printerId, callback);
+ mCallbacks.onRequestCustomPrinterIcon(printerId, cancellationSignal, callback);
}
}
diff --git a/core/tests/coretests/src/android/view/ViewCaptureTest.java b/core/tests/coretests/src/android/view/ViewCaptureTest.java
new file mode 100644
index 0000000..15cfe23
--- /dev/null
+++ b/core/tests/coretests/src/android/view/ViewCaptureTest.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package android.view;
+
+import android.app.Activity;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.support.test.filters.SmallTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
+import android.util.SparseIntArray;
+
+import com.android.frameworks.coretests.R;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import static org.junit.Assert.assertTrue;
+
+@RunWith(AndroidJUnit4.class)
+public class ViewCaptureTest {
+
+ private static final SparseIntArray EXPECTED_CHILDREN_VISIBILITY = new SparseIntArray();
+ static {
+ EXPECTED_CHILDREN_VISIBILITY.append(R.id.child1, View.VISIBLE);
+ EXPECTED_CHILDREN_VISIBILITY.append(R.id.child2, View.INVISIBLE);
+ EXPECTED_CHILDREN_VISIBILITY.append(R.id.child3, View.GONE);
+ EXPECTED_CHILDREN_VISIBILITY.append(R.id.child4, View.VISIBLE);
+ }
+
+ @Rule
+ public ActivityTestRule<ViewCaptureTestActivity> mActivityRule = new ActivityTestRule<>(
+ ViewCaptureTestActivity.class);
+
+ private Activity mActivity;
+ private ViewGroup mViewToCapture;
+
+ @Before
+ public void setUp() throws Exception {
+ mActivity = mActivityRule.getActivity();
+ mViewToCapture = (ViewGroup) mActivity.findViewById(R.id.capture);
+ }
+
+ @Test
+ @SmallTest
+ public void testCreateSnapshot() {
+ assertChildrenVisibility();
+ testCreateSnapshot(true, R.drawable.view_capture_test_no_children_golden);
+ assertChildrenVisibility();
+ testCreateSnapshot(false, R.drawable.view_capture_test_with_children_golden);
+ assertChildrenVisibility();
+ }
+
+ private void testCreateSnapshot(boolean skipChildren, int goldenResId) {
+ Bitmap result = mViewToCapture.createSnapshot(Bitmap.Config.ARGB_8888, 0, skipChildren);
+ Bitmap golden = BitmapFactory.decodeResource(mActivity.getResources(), goldenResId);
+ assertTrue(golden.sameAs(result));
+ }
+
+ private void assertChildrenVisibility() {
+ for (int i = 0; i < EXPECTED_CHILDREN_VISIBILITY.size(); i++) {
+ int id = EXPECTED_CHILDREN_VISIBILITY.keyAt(i);
+ View child = mViewToCapture.findViewById(id);
+ Assert.assertEquals(EXPECTED_CHILDREN_VISIBILITY.get(id), child.getVisibility());
+ }
+ }
+}
diff --git a/core/tests/coretests/src/android/view/ViewCaptureTestActivity.java b/core/tests/coretests/src/android/view/ViewCaptureTestActivity.java
new file mode 100644
index 0000000..20e3eb5
--- /dev/null
+++ b/core/tests/coretests/src/android/view/ViewCaptureTestActivity.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package android.view;
+
+import android.annotation.Nullable;
+import android.app.Activity;
+import android.os.Bundle;
+import com.android.frameworks.coretests.R;
+
+public class ViewCaptureTestActivity extends Activity {
+ @Override
+ protected void onCreate(@Nullable Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.view_capture_snapshot);
+ }
+}
diff --git a/core/tests/coretests/src/android/widget/SuggestionsPopupWindowTest.java b/core/tests/coretests/src/android/widget/SuggestionsPopupWindowTest.java
index a37abf1..59ffd56 100644
--- a/core/tests/coretests/src/android/widget/SuggestionsPopupWindowTest.java
+++ b/core/tests/coretests/src/android/widget/SuggestionsPopupWindowTest.java
@@ -20,6 +20,7 @@
import android.content.res.TypedArray;
import android.test.ActivityInstrumentationTestCase2;
import android.test.suitebuilder.annotation.SmallTest;
+import android.test.suitebuilder.annotation.Suppress;
import android.text.Selection;
import android.text.SpannableStringBuilder;
import android.text.Spanned;
@@ -42,6 +43,7 @@
}
@SmallTest
+ @Suppress
public void testTextAppearanceInSuggestionsPopup() {
final Activity activity = getActivity();
diff --git a/core/tests/coretests/src/android/widget/TextViewActivityMouseTest.java b/core/tests/coretests/src/android/widget/TextViewActivityMouseTest.java
index 3fbc16a..923b829 100644
--- a/core/tests/coretests/src/android/widget/TextViewActivityMouseTest.java
+++ b/core/tests/coretests/src/android/widget/TextViewActivityMouseTest.java
@@ -44,7 +44,6 @@
import android.support.test.espresso.Espresso;
import android.test.ActivityInstrumentationTestCase2;
import android.test.suitebuilder.annotation.SmallTest;
-import android.test.suitebuilder.annotation.Suppress;
import android.view.MotionEvent;
import android.widget.espresso.ContextMenuUtils;
@@ -98,7 +97,6 @@
}
@SmallTest
- @Suppress
public void testContextMenu() throws Exception {
final String text = "abc def ghi.";
onView(withId(R.id.textview)).perform(click());
diff --git a/core/tests/coretests/src/android/widget/TextViewActivityTest.java b/core/tests/coretests/src/android/widget/TextViewActivityTest.java
index f779d6c..ecf88f1 100644
--- a/core/tests/coretests/src/android/widget/TextViewActivityTest.java
+++ b/core/tests/coretests/src/android/widget/TextViewActivityTest.java
@@ -675,4 +675,26 @@
assertFloatingToolbarContainsItem(
getActivity().getString(com.android.internal.R.string.copy));
}
+
+ @SmallTest
+ public void testTransientState() throws Exception {
+ final String text = "abc def";
+ onView(withId(R.id.textview)).perform(click());
+ onView(withId(R.id.textview)).perform(replaceText(text));
+
+ final TextView textView = (TextView) getActivity().findViewById(R.id.textview);
+ assertFalse(textView.hasTransientState());
+
+ onView(withId(R.id.textview)).perform(longPressOnTextAtIndex(text.indexOf('b')));
+ // hasTransientState should return true when user generated selection is active.
+ assertTrue(textView.hasTransientState());
+ onView(withId(R.id.textview)).perform(clickOnTextAtIndex(text.indexOf('d')));
+ // hasTransientState should return false as the selection has been cleared.
+ assertFalse(textView.hasTransientState());
+ textView.post(
+ () -> Selection.setSelection((Spannable) textView.getText(), 0, text.length()));
+ getInstrumentation().waitForIdleSync();
+ // hasTransientState should return false when selection is created by API.
+ assertFalse(textView.hasTransientState());
+ }
}
diff --git a/core/tests/coretests/src/android/widget/espresso/MouseClickAction.java b/core/tests/coretests/src/android/widget/espresso/MouseClickAction.java
index b8ea2de..bec4180 100644
--- a/core/tests/coretests/src/android/widget/espresso/MouseClickAction.java
+++ b/core/tests/coretests/src/android/widget/espresso/MouseClickAction.java
@@ -21,7 +21,6 @@
import android.support.test.espresso.UiController;
import android.support.test.espresso.ViewAction;
import android.support.test.espresso.action.CoordinatesProvider;
-import android.support.test.espresso.action.GeneralClickAction;
import android.support.test.espresso.action.MotionEvents;
import android.support.test.espresso.action.MotionEvents.DownResultHolder;
import android.support.test.espresso.action.Press;
@@ -34,7 +33,7 @@
* ViewAction for performing an click on View by a mouse.
*/
public final class MouseClickAction implements ViewAction {
- private final GeneralClickAction mGeneralClickAction;
+ private final ViewClickAction mViewClickAction;
@MouseUiController.MouseButton
private final int mButton;
@@ -100,30 +99,22 @@
*/
public MouseClickAction(Tapper tapper, CoordinatesProvider coordinatesProvider,
@MouseUiController.MouseButton int button) {
- mGeneralClickAction = new GeneralClickAction(tapper, coordinatesProvider, Press.PINPOINT);
+ mViewClickAction = new ViewClickAction(tapper, coordinatesProvider, Press.PINPOINT);
mButton = button;
}
@Override
public Matcher<View> getConstraints() {
- return mGeneralClickAction.getConstraints();
+ return mViewClickAction.getConstraints();
}
@Override
public String getDescription() {
- return mGeneralClickAction.getDescription();
+ return mViewClickAction.getDescription();
}
@Override
public void perform(UiController uiController, View view) {
- mGeneralClickAction.perform(new MouseUiController(uiController, mButton), view);
- long doubleTapTimeout = ViewConfiguration.getDoubleTapTimeout();
- if (0 < doubleTapTimeout) {
- // Wait to avoid false gesture detection. Without this wait, consecutive clicks can be
- // detected as a triple click. e.g. 2 double clicks are detected as a triple click and
- // a single click because espresso isn't aware of triple click detection logic, which
- // is TextView specific gesture.
- uiController.loopMainThreadForAtLeast(doubleTapTimeout);
- }
+ mViewClickAction.perform(new MouseUiController(uiController, mButton), view);
}
}
diff --git a/core/tests/coretests/src/android/widget/espresso/TextViewActions.java b/core/tests/coretests/src/android/widget/espresso/TextViewActions.java
index 4cecb65..335d021 100644
--- a/core/tests/coretests/src/android/widget/espresso/TextViewActions.java
+++ b/core/tests/coretests/src/android/widget/espresso/TextViewActions.java
@@ -17,15 +17,10 @@
package android.widget.espresso;
import static android.support.test.espresso.action.ViewActions.actionWithAssertions;
-
-import org.hamcrest.core.Is;
-import org.hamcrest.core.IsInstanceOf;
-
import android.graphics.Rect;
import android.support.test.espresso.PerformException;
import android.support.test.espresso.ViewAction;
import android.support.test.espresso.action.CoordinatesProvider;
-import android.support.test.espresso.action.GeneralClickAction;
import android.support.test.espresso.action.Press;
import android.support.test.espresso.action.Tap;
import android.support.test.espresso.util.HumanReadables;
@@ -55,7 +50,7 @@
*/
public static ViewAction clickOnTextAtIndex(int index) {
return actionWithAssertions(
- new GeneralClickAction(Tap.SINGLE, new TextCoordinates(index), Press.FINGER));
+ new ViewClickAction(Tap.SINGLE, new TextCoordinates(index), Press.FINGER));
}
/**
@@ -101,7 +96,7 @@
*/
public static ViewAction doubleClickOnTextAtIndex(int index) {
return actionWithAssertions(
- new GeneralClickAction(Tap.DOUBLE, new TextCoordinates(index), Press.FINGER));
+ new ViewClickAction(Tap.DOUBLE, new TextCoordinates(index), Press.FINGER));
}
/**
@@ -131,7 +126,7 @@
*/
public static ViewAction longPressOnTextAtIndex(int index) {
return actionWithAssertions(
- new GeneralClickAction(Tap.LONG, new TextCoordinates(index), Press.FINGER));
+ new ViewClickAction(Tap.LONG, new TextCoordinates(index), Press.FINGER));
}
/**
diff --git a/core/tests/coretests/src/android/widget/espresso/ViewClickAction.java b/core/tests/coretests/src/android/widget/espresso/ViewClickAction.java
new file mode 100644
index 0000000..8bce1b0
--- /dev/null
+++ b/core/tests/coretests/src/android/widget/espresso/ViewClickAction.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.widget.espresso;
+
+import org.hamcrest.Matcher;
+
+import android.support.test.espresso.UiController;
+import android.support.test.espresso.ViewAction;
+import android.support.test.espresso.action.CoordinatesProvider;
+import android.support.test.espresso.action.GeneralClickAction;
+import android.support.test.espresso.action.PrecisionDescriber;
+import android.support.test.espresso.action.Tapper;
+import android.view.View;
+import android.view.ViewConfiguration;
+
+public final class ViewClickAction implements ViewAction {
+ private final GeneralClickAction mGeneralClickAction;
+
+ public ViewClickAction(Tapper tapper, CoordinatesProvider coordinatesProvider,
+ PrecisionDescriber precisionDescriber) {
+ mGeneralClickAction = new GeneralClickAction(tapper, coordinatesProvider,
+ precisionDescriber);
+ }
+
+ @Override
+ public Matcher<View> getConstraints() {
+ return mGeneralClickAction.getConstraints();
+ }
+
+ @Override
+ public String getDescription() {
+ return mGeneralClickAction.getDescription();
+ }
+
+ @Override
+ public void perform(UiController uiController, View view) {
+ mGeneralClickAction.perform(uiController, view);
+ long doubleTapTimeout = ViewConfiguration.getDoubleTapTimeout();
+ if (0 < doubleTapTimeout) {
+ // Wait to avoid false gesture detection. Without this wait, consecutive clicks can be
+ // detected as a double click or triple click. e.g. 2 double clicks on TextView are
+ // detected as a triple click and a single click because espresso isn't aware of
+ // TextView specific gestures.
+ uiController.loopMainThreadForAtLeast(doubleTapTimeout);
+ }
+ }
+}
diff --git a/core/tests/coretests/src/com/android/internal/policy/PhoneWindowActionModeTest.java b/core/tests/coretests/src/com/android/internal/policy/PhoneWindowActionModeTest.java
index 7519627..2a24881 100644
--- a/core/tests/coretests/src/com/android/internal/policy/PhoneWindowActionModeTest.java
+++ b/core/tests/coretests/src/com/android/internal/policy/PhoneWindowActionModeTest.java
@@ -22,7 +22,6 @@
import android.view.ActionMode;
import android.view.ActionMode.Callback;
import android.view.KeyEvent;
-import android.view.KeyboardShortcutGroup;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
diff --git a/data/fonts/Android.mk b/data/fonts/Android.mk
index fd28f64..e3639ec 100644
--- a/data/fonts/Android.mk
+++ b/data/fonts/Android.mk
@@ -101,8 +101,13 @@
checkbuild: fontchain_lint
FONTCHAIN_LINTER := frameworks/base/tools/fonts/fontchain_lint.py
+ifeq ($(SMALLER_FONT_FOOTPRINT),true)
+CHECK_EMOJI := false
+else
+CHECK_EMOJI := true
+endif
.PHONY: fontchain_lint
fontchain_lint: $(FONTCHAIN_LINTER) $(TARGET_OUT)/etc/fonts.xml
PYTHONPATH=$$PYTHONPATH:external/fonttools/Lib \
- python $(FONTCHAIN_LINTER) $(TARGET_OUT) external/unicode
+ python $(FONTCHAIN_LINTER) $(TARGET_OUT) $(CHECK_EMOJI) external/unicode
diff --git a/docs/docs-redirect-index.html b/docs/docs-redirect-index.html
index dc0bc72..ea5f186 100644
--- a/docs/docs-redirect-index.html
+++ b/docs/docs-redirect-index.html
@@ -1,8 +1,8 @@
-<html>
-<head>
-<meta http-equiv="refresh" content="0;url=framework/index.html">
-</head>
-<body>
-<a href="framework/index.html">click here if you are not redirected</a>
-</body>
-</html>
+<html>
+<head>
+<meta http-equiv="refresh" content="0;url=framework/index.html">
+</head>
+<body>
+<a href="framework/index.html">click here if you are not redirected</a>
+</body>
+</html>
diff --git a/docs/docs-redirect.html b/docs/docs-redirect.html
index 4e0743e..d83564c 100644
--- a/docs/docs-redirect.html
+++ b/docs/docs-redirect.html
@@ -1,8 +1,8 @@
-<html>
-<head>
-<meta http-equiv="refresh" content="0;url=docs/offline.html">
-</head>
-<body>
-<a href="docs/offline.html">click here if you are not redirected</a>
-</body>
-</html>
+<html>
+<head>
+<meta http-equiv="refresh" content="0;url=docs/offline.html">
+</head>
+<body>
+<a href="docs/offline.html">click here if you are not redirected</a>
+</body>
+</html>
diff --git a/docs/docs-samples-redirect.html b/docs/docs-samples-redirect.html
index 4e549e6..abefe6c 100644
--- a/docs/docs-samples-redirect.html
+++ b/docs/docs-samples-redirect.html
@@ -1,8 +1,8 @@
-<html>
-<head>
-<meta http-equiv="refresh" content="0;url=../../samples/">
-</head>
-<body>
-<a href="../../samples/">click here if you are not redirected</a>
-</body>
-</html>
+<html>
+<head>
+<meta http-equiv="refresh" content="0;url=../../samples/">
+</head>
+<body>
+<a href="../../samples/">click here if you are not redirected</a>
+</body>
+</html>
diff --git a/docs/html/guide/topics/renderscript/reference/overview.jd b/docs/html/guide/topics/renderscript/reference/overview.jd
index 5e824ee..017a713 100644
--- a/docs/html/guide/topics/renderscript/reference/overview.jd
+++ b/docs/html/guide/topics/renderscript/reference/overview.jd
@@ -611,7 +611,7 @@
</tr>
</tbody></table>
<h2>Conversion Functions</h2>
-<p> The functions below convert from a numerical vector type to another, of from one color
+<p> The functions below convert from a numerical vector type to another, or from one color
representation to another.
</p>
<table class='jd-sumtable'><tbody>
diff --git a/docs/html/guide/topics/renderscript/reference/rs_convert.jd b/docs/html/guide/topics/renderscript/reference/rs_convert.jd
index d4bf77fa..89fd040 100644
--- a/docs/html/guide/topics/renderscript/reference/rs_convert.jd
+++ b/docs/html/guide/topics/renderscript/reference/rs_convert.jd
@@ -4,7 +4,7 @@
<div class='renderscript'>
<h2>Overview</h2>
-<p> The functions below convert from a numerical vector type to another, of from one color
+<p> The functions below convert from a numerical vector type to another, or from one color
representation to another.
</p>
<h2>Summary</h2>
diff --git a/docs/html/guide/topics/resources/localization.jd b/docs/html/guide/topics/resources/localization.jd
index 0a96a15..e60ca9f 100644
--- a/docs/html/guide/topics/resources/localization.jd
+++ b/docs/html/guide/topics/resources/localization.jd
@@ -1,484 +1,484 @@
-page.title=Localizing with Resources
-parent.title=Application Resources
-page.tags="localizing","localization","resources", "formats", "l10n"
-parent.link=index.html
-@jd:body
-
-<div id="qv-wrapper">
- <div id="qv">
-
-<h2>Quickview</h2>
-
-<ul>
- <li>Use resource sets to create a localized app.</li>
- <li>Android loads the correct resource set for the user's language and locale.</li>
- <li>If localized resources are not available, Android loads your default resources.</li>
-</ul>
-
-<h2>In this document</h2>
-<ol>
- <li><a href="#resource-switching">Overview: Resource-Switching in Android</a></li>
-<li><a href="#using-framework">Using Resources for Localization</a></li>
-<li><a href="#strategies">Localization Tips</a></li>
-<li><a href="#testing">Testing Localized Applications</a></li>
-</ol>
-
-<h2>See also</h2>
- <ol>
- <li><a href="{@docRoot}distribute/tools/localization-checklist.html">Localization Checklist</a></li>
- <li><a href="{@docRoot}guide/topics/resources/providing-resources.html">Providing Resources</a></li>
- <li><a href="{@docRoot}guide/topics/ui/declaring-layout.html">Layouts</a></li>
- <li><a href="{@docRoot}reference/android/app/Activity.html#ActivityLifecycle">Activity Lifecycle</a></li>
-</ol>
-</div>
-</div>
-
-<p>Android will run on many devices in many regions. To reach the most users,
-your application should handle text, audio files, numbers, currency, and
-graphics in ways appropriate to the locales where your application will be used.
-</p>
-
-<p>This document describes best practices for localizing Android
-applications. The principles apply whether you are developing your application
-using ADT with Eclipse, Ant-based tools, or any other IDE. </p>
-
-<p>You should already have a working knowledge of Java and be familiar with
-Android resource loading, the declaration of user interface elements in XML,
-development considerations such as Activity lifecycle, and general principles of
-internationalization and localization. </p>
-
-<p>It is good practice to use the Android resource framework to separate the
-localized aspects of your application as much as possible from the core Java
-functionality:</p>
-
-<ul>
- <li>You can put most or all of the <em>contents</em> of your application's
-user interface into resource files, as described in this document and in <a
-href="{@docRoot}guide/topics/resources/providing-resources.html">Providing Resources</a>.</li>
- <li>The <em>behavior</em> of the user interface, on the other hand, is driven
-by your Java code.
- For example, if users input data that needs to be formatted or sorted
-differently depending on locale, then you would use Java to handle the data
-programmatically. This document does not cover how to localize your Java code.
-</li>
-</ul>
-
-<p>For a short guide to localizing strings in your app, see the training lesson, <a
-href="{@docRoot}training/basics/supporting-devices/languages.html">Supporting Different Languages</a>. </p>
-
-
-<h2 id="resource-switching">Overview: Resource-Switching in Android</h2>
-
-<p>Resources are text strings, layouts, sounds, graphics, and any other static
-data that your Android application needs. An application can include multiple
-sets of resources, each customized for a different device configuration. When a
-user runs the application, Android automatically selects and loads the
-resources that best match the device.</p>
-
-<p>(This document focuses on localization and locale. For a complete description
-of resource-switching and all the types of configurations that you can
-specify — screen orientation, touchscreen type, and so on — see <a
-href="{@docRoot}guide/topics/resources/providing-resources.html#AlternativeResources">Providing
-Alternative Resources</a>.)</p>
-
-<table border="0" cellspacing="0" cellpadding="0">
- <tr border="0">
- <td width="180" style="border: 0pt none ;"><p class="special-note">
- <strong>When you write your application:</strong>
- <br><br>
- You create a set of default resources, plus alternatives to be used in
- different locales.</p></td>
- <td style="border: 0pt none; padding:0">
- <p style="border:0; padding:0"><img src="../../../images/resources/right-arrow.png" alt="right-arrow"
- width="51" height="17"></p></td>
- <td width="180" style="border: 0pt none ;"><p class="special-note">
- <strong>When a user runs your application:</strong>
- <br><br>The Android system selects which resources to load, based on the
- device's locale.</p></td>
- </tr>
-</table>
-
-<p>When you write your application, you create default and alternative resources
-for your application to use. To create resources, you place files within
-specially named subdirectories of the project's <code>res/</code> directory.
-</p>
-
-
-
-<h3 id="defaults-r-important">Why Default Resources Are Important</h3>
-
-<p>Whenever the application runs in a locale for which you have not provided
-locale-specific text, Android will load the default strings from
-<code>res/values/strings.xml</code>. If this default file is absent, or if it
-is missing a string that your application needs, then your application will not run
-and will show an error.
-The example below illustrates what can happen when the default text file is incomplete. </p>
-
-<p><em>Example:</em>
-<p>An application's Java code refers to just two strings, <code>text_a</code> and
- <code>text_b</code>. This application includes a localized resource file
- (<code>res/values-en/strings.xml</code>) that defines <code>text_a</code> and
- <code>text_b</code> in English. This application also includes a default
- resource file (<code>res/values/strings.xml</code>) that includes a
-definition for <code>text_a</code>, but not for <code>text_b</code>:
-<ul>
- <li>This application might compile without a problem. An IDE such as Eclipse
- will not highlight any errors if a resource is missing.</li>
- <li>When this application is launched on a device with locale set to English,
- the application might run without a problem, because
- <code>res/values-en/strings.xml</code> contains both of the needed text
- strings.</li>
- <li>However, <strong>the user will see an error message and a Force Close
- button</strong> when this application is launched on a device set to a
- language other than English. The application will not load.</li>
-</ul>
-
-
-<p>To prevent this situation, make sure that a <code>res/values/strings.xml</code>
- file exists and that it defines every needed string. The situation applies to
- all types of resources, not just strings: You
- need to create a set of default resource files containing all
- the resources that your application calls upon — layouts, drawables,
- animations, etc. For information about testing, see <a href="#test-for-default">
- Testing for Default Resources</a>.</p>
-
-<h2 id="using-framework">Using Resources for Localization</h2>
-
-<h3 id="creating-defaults">How to Create Default Resources</h3>
-
-<p>Put the application's default text in
-a file with the following location and name:</p>
-<p><code> res/values/strings.xml</code> (required directory)</p>
-
-<p>The text strings in <code>res/values/strings.xml</code> should use the
-default language, which is the language that you expect most of your application's users to
-speak. </p>
-
-<p>The default resource set must also include any default drawables and layouts,
- and can include other types of resources such as animations.
-<br>
- <code> res/drawable/</code>(required directory holding at least
- one graphic file, for the application's icon on Google Play)<br>
- <code> res/layout/</code> (required directory holding an XML
- file that defines the default layout)<br>
- <code> res/anim/</code> (required if you have any
- <code>res/anim-<em><qualifiers></em></code> folders)<br>
- <code> res/xml/</code> (required if you have any
- <code>res/xml-<em><qualifiers></em></code> folders)<br>
- <code> res/raw/</code> (required if you have any
- <code>res/raw-<em><qualifiers></em></code> folders)
-</p>
-
-<p class="note"><strong>Tip:</strong> In your code, examine each reference to
- an Android resource. Make sure that a default resource is defined for each
- one. Also make sure that the default string file is complete: A <em>
- localized</em> string file can contain a subset of the strings, but the
- <em>default</em> string file must contain them all.
-</p>
-
-<h3 id="creating-alternatives">How to Create Alternative Resources</h3>
-
-<p>A large part of localizing an application is providing alternative text for
-different languages. In some cases you will also provide alternative graphics,
-sounds, layouts, and other locale-specific resources. </p>
-
-<p>An application can specify many <code>res/<em><qualifiers></em>/</code>
-directories, each with different qualifiers. To create an alternative resource for
-a different locale, you use a qualifier that specifies a language or a
-language-region combination. (The name of a resource directory must conform
-to the naming scheme described in
-<a href="{@docRoot}guide/topics/resources/providing-resources.html#AlternativeResources">Providing
-Alternative Resources</a>,
-or else it will not compile.)</p>
-
-<p><em>Example:</em></p>
-
-<p>Suppose that your application's default language is English. Suppose also
-that you want to localize all the text in your application to French, and most
-of the text in your application (everything except the application's title) to
-Japanese. In this case, you could create three alternative <code>strings.xml</code>
-files, each stored in a locale-specific resource directory:</p>
-
-<ol>
- <li><code>res/values/strings.xml</code><br>
- Contains English text for all the strings that the application uses,
-including text for a string named <code>title</code>.</li>
- <li><code>res/values-fr/strings.xml</code><br>
- Contain French text for all the strings, including <code>title</code>.</li>
- <li><code>res/values-ja/strings.xml</code><br>
- Contain Japanese text for all the strings <em>except</em>
-<code>title</code>.<br>
- <code></code></li>
-</ol>
-
-<p>If your Java code refers to <code>R.string.title</code>, here is what will
-happen at runtime:</p>
-
-<ul>
- <li>If the device is set to any language other than French, Android will load
-<code>title</code> from the <code>res/values/strings.xml</code> file.</li>
- <li>If the device is set to French, Android will load <code>title</code> from
-the <code>res/values-fr/strings.xml</code> file.</li>
-</ul>
-
-<p>Notice that if the device is set to Japanese, Android will look for
-<code>title</code> in the <code>res/values-ja/strings.xml</code> file. But
-because no such string is included in that file, Android will fall back to the
-default, and will load <code>title</code> in English from the
-<code>res/values/strings.xml</code> file. </p>
-
-<h3 id="resource-precedence">Which Resources Take Precedence?</h3>
-
-<p> If multiple resource files match a device's configuration, Android follows a
-set of rules in deciding which file to use. Among the qualifiers that can be
-specified in a resource directory name, <strong>locale almost always takes
-precedence</strong>. </p>
-<p><em>Example:</em></p>
-
-<p>Assume that an application includes a default set of graphics and two other
-sets of graphics, each optimized for a different device setup:</p>
-
-<ul>
- <li><code>res/drawable/</code><br>
- Contains
- default graphics.</li>
- <li><code>res/drawable-small-land-stylus/</code><br>
- Contains graphics optimized for use with a device that expects input from a
- stylus and has a QVGA low-density screen in landscape orientation.</li>
- <li><code>res/drawable-ja/</code> <br>
- Contains graphics optimized for use with Japanese.</li>
-</ul>
-
-<p>If the application runs on a device that is configured to use Japanese,
-Android will load graphics from <code>res/drawable-ja/</code>, even if the
-device happens to be one that expects input from a stylus and has a QVGA
-low-density screen in landscape orientation.</p>
-
-<p class="note"><strong>Exception:</strong> The only qualifiers that take
-precedence over locale in the selection process are MCC and MNC (mobile country
-code and mobile network code). </p>
-
-<p><em>Example:</em></p>
-
-<p>Assume that you have the following situation:</p>
-
-<ul>
- <li>The application code calls for <code>R.string.text_a</code></li>
- <li>Two relevant resource files are available:
- <ul>
- <li><code>res/values-mcc404/strings.xml</code>, which includes
-<code>text_a</code> in the application's default language, in this case
-English.</li>
- <li><code>res/values-hi/strings.xml</code>, which includes
-<code>text_a</code> in Hindi.</li>
- </ul>
- </li>
- <li>The application is running on a device that has the following
-configuration:
- <ul>
- <li>The SIM card is connected to a mobile network in India (MCC 404).</li>
- <li>The language is set to Hindi (<code>hi</code>).</li>
- </ul>
- </li>
-</ul>
-
-<p>Android will load <code>text_a</code> from
-<code>res/values-mcc404/strings.xml</code> (in English), even if the device is
-configured for Hindi. That is because in the resource-selection process, Android
-will prefer an MCC match over a language match. </p>
-
-<p>The selection process is not always as straightforward as these examples
-suggest. Please read <a
-href="{@docRoot}guide/topics/resources/providing-resources.html#BestMatch">How Android Finds
-the Best-matching Resource</a> for a more nuanced description of the
-process. All the qualifiers are described and listed in order of
-precedence in <a
-href="{@docRoot}guide/topics/resources/providing-resources.html#table2">Table 2 of Providing
-Alternative Resources</a>.</p>
-
-<h3 id="referring-to-resources">Referring to Resources in Java</h3>
-
-<p>In your application's Java code, you refer to resources using the syntax
-<code>R.<em>resource_type</em>.<em>resource_name</em></code> or
-<code>android.R.<em>resource_type</em>.<em>resource_name</em></code><em>.</em>
-For more about this, see <a
-href="{@docRoot}guide/topics/resources/accessing-resources.html">Accessing Resources</a>.</p>
-
-<h2 id="checklist">Localization Checklist</h2>
-
-<p>For a complete overview of the process of localizing and distributing an Android application,
-see the <a href="{@docRoot}distribute/tools/localization-checklist.html">Localization
-Checklist</a> document.</p>
-
-<h2 id="strategies">Localization Tips</h2>
-
-<h4 id="failing2">Design your application to work in any locale</h4>
-
-<p>You cannot assume anything about the device on which a user will
-run your application. The device might have hardware that you were not
-anticipating, or it might be set to a locale that you did not plan for or that
-you cannot test. Design your application so that it will function normally or fail gracefully no
-matter what device it runs on.</p>
-
-<p class="note"><strong>Important:</strong> Make sure that your application
-includes a full set of default resources.</p> <p>Make sure to include
-<code>res/drawable/</code> and a <code>res/values/</code> folders (without any
-additional modifiers in the folder names) that contain all the images and text
-that your application will need. </p>
-
-<p>If an application is missing even one default resource, it will not run on a
- device that is set to an unsupported locale. For example, the
- <code>res/values/strings.xml</code> default file might lack one string that
- the application needs: When the application runs in an unsupported locale and
- attempts to load <code>res/values/strings.xml</code>, the user will see an
- error message and a Force Close button. An IDE such as Eclipse will not
- highlight this kind of error, and you will not see the problem when you
- test the application on a device or emulator that is set to a supported locale.</p>
-
-<p>For more information, see <a href="#test-for-default">Testing for Default Resources</a>.</p>
-
-<h4>Design a flexible layout</h4>
-
-<p> If you need to rearrange your layout to fit a certain language (for example
-German with its long words), you can create an alternative layout for that
-language (for example <code>res/layout-de/main.xml</code>). However, doing this
-can make your application harder to maintain. It is better to create a single
-layout that is more flexible.</p>
-
-<p>Another typical situation is a language that requires something different in
-its layout. For example, you might have a contact form that should include two
-name fields when the application runs in Japanese, but three name fields when
-the application runs in some other language. You could handle this in either of
-two ways:</p>
-
-<ul>
- <li>Create one layout with a field that you can programmatically enable or
-disable, based on the language, or</li>
- <li>Have the main layout include another layout that includes the changeable
-field. The second layout can have different configurations for different
-languages.</li>
-</ul>
-
-<h4>Avoid creating more resource files and text strings than you need</h4>
-
-<p>You probably do not need to create a locale-specific
-alternative for every resource in your application. For example, the layout
-defined in the <code>res/layout/main.xml</code> file might work in any locale,
-in which case there would be no need to create any alternative layout files.
-</p>
-
-<p>Also, you might not need to create alternative text for every
-string. For example, assume the following:</p>
-
-<ul>
- <li>Your application's default language is American
-English. Every string that the application uses is defined, using American
-English spellings, in <code>res/values/strings.xml</code>. </li>
-
- <li>For a few important phrases, you want to provide
-British English spelling. You want these alternative strings to be used when your
-application runs on a device in the United Kingdom. </li>
-</ul>
-
-<p>To do this, you could create a small file called
-<code>res/values-en-rGB/strings.xml</code> that includes only the strings that
-should be different when the application runs in the U.K. For all the rest of
-the strings, the application will fall back to the defaults and use what is
-defined in <code>res/values/strings.xml</code>.</p>
-
-<h4>Use the Android Context object for manual locale lookup</h4>
-
-<p>You can look up the locale using the {@link android.content.Context} object
-that Android makes available:</p>
-
-<pre>String locale = context.getResources().getConfiguration().locale.getDisplayName();</pre>
-
-<h2 id="testing">Testing Localized Applications</h2>
-
-<h3 id="device">Testing on a Device</h3>
-<p>Keep in mind that the device you are testing may be significantly different from
- the devices available to consumers in other geographies. The locales available
- on your device may differ from those available on other devices. Also, the
- resolution and density of the device screen may differ, which could affect
- the display of strings and drawables in your UI.</p>
-
-<p>To change the locale or language on a device, use the Settings application.</p>
-
-<h3 id="emulator">Testing on an Emulator</h3>
-
-<p>For details about using the emulator, see See <a
-href="{@docRoot}tools/help/emulator.html">Android Emulator</a>.</p>
-<h4>Creating and using a custom locale</h4>
-
-<p>A "custom" locale is a language/region combination that the Android
-system image does not explicitly support. (For a list of supported locales in
-Android platforms see the Version Notes in the <a
-href="{@docRoot}sdk/index.html">SDK</a> tab). You can test
-how your application will run in a custom locale by creating a custom locale in
-the emulator. There are two ways to do this:</p>
-
-<ul>
- <li>Use the Custom Locale application, which is accessible from the
-Application tab. (After you create a custom locale, switch to it by
-pressing and holding the locale name.)</li>
- <li>Change to a custom locale from the adb shell, as described below.</li>
-</ul>
-
-<p>When you set the emulator to a locale that is not available in the Android
-system image, the system itself will display in its default language. Your
-application, however, should localize properly.</p>
-
-<h4>Changing the emulator locale from the adb shell</h4>
-
-<p>To change the locale in the emulator by using the adb shell. </p>
-
-<ol>
- <li>Pick the locale you want to test and determine its BCP-47 language tag, for
-example, Canadian French would be <code>fr-CA</code>.<br>
- </li>
- <li>Launch an emulator.</li>
- <li>From a command-line shell on the host computer, run the following
-command:<br>
- <code>adb shell</code><br>
- or if you have a device attached, specify that you want the emulator by adding
-the <code>-e</code> option:<br>
- <code>adb -e shell</code></li>
- <li>At the adb shell prompt (<code>#</code>), run this command: <br>
- <code>setprop persist.sys.locale [<em>BCP-47 language tag</em>];stop;sleep 5;start <br>
- </code>Replace bracketed sections with the appropriate codes from Step
-1.</li>
-</ol>
-
-<p>For instance, to test in Canadian French:</p>
-
-<p><code>setprop persist.sys.locale fr-CA;stop;sleep 5;start </code></p>
-
-<p>This will cause the emulator to restart. (It will look like a full reboot,
-but it is not.) Once the Home screen appears again, re-launch your application (for
-example, click the Run icon in Eclipse), and the application will launch with
-the new locale. </p>
-
-<h3 id="test-for-default">Testing for Default Resources</h3>
-<p>Here's how to test whether an application includes every string resource that it needs: </p>
-<ol><li>Set the emulator or device to a language that your application does not
- support. For example, if the application has French strings in
- <code>res/values-fr/</code> but does not have any Spanish strings in
- <code>res/values-es/</code>, then set the emulator's locale to Spanish.
- (You can use the Custom Locale application to set the emulator to an
- unsupported locale.)</li>
- <li>Run the application.</li>
-<li>If the application shows an error message and a Force Close button, it might
- be looking for a string that is not available. Make sure that your
- <code>res/values/strings.xml</code> file includes a definition for
- every string that the application uses.</li>
-</ol>
-</p>
-
-<p>If the test is successful, repeat it for other types of
- configurations. For example, if the application has a layout file called
- <code>res/layout-land/main.xml</code> but does not contain a file called
- <code>res/layout-port/main.xml</code>, then set the emulator or device to
- portrait orientation and see if the application will run.
-
-
-
+page.title=Localizing with Resources
+parent.title=Application Resources
+page.tags="localizing","localization","resources", "formats", "l10n"
+parent.link=index.html
+@jd:body
+
+<div id="qv-wrapper">
+ <div id="qv">
+
+<h2>Quickview</h2>
+
+<ul>
+ <li>Use resource sets to create a localized app.</li>
+ <li>Android loads the correct resource set for the user's language and locale.</li>
+ <li>If localized resources are not available, Android loads your default resources.</li>
+</ul>
+
+<h2>In this document</h2>
+<ol>
+ <li><a href="#resource-switching">Overview: Resource-Switching in Android</a></li>
+<li><a href="#using-framework">Using Resources for Localization</a></li>
+<li><a href="#strategies">Localization Tips</a></li>
+<li><a href="#testing">Testing Localized Applications</a></li>
+</ol>
+
+<h2>See also</h2>
+ <ol>
+ <li><a href="{@docRoot}distribute/tools/localization-checklist.html">Localization Checklist</a></li>
+ <li><a href="{@docRoot}guide/topics/resources/providing-resources.html">Providing Resources</a></li>
+ <li><a href="{@docRoot}guide/topics/ui/declaring-layout.html">Layouts</a></li>
+ <li><a href="{@docRoot}reference/android/app/Activity.html#ActivityLifecycle">Activity Lifecycle</a></li>
+</ol>
+</div>
+</div>
+
+<p>Android will run on many devices in many regions. To reach the most users,
+your application should handle text, audio files, numbers, currency, and
+graphics in ways appropriate to the locales where your application will be used.
+</p>
+
+<p>This document describes best practices for localizing Android
+applications. The principles apply whether you are developing your application
+using ADT with Eclipse, Ant-based tools, or any other IDE. </p>
+
+<p>You should already have a working knowledge of Java and be familiar with
+Android resource loading, the declaration of user interface elements in XML,
+development considerations such as Activity lifecycle, and general principles of
+internationalization and localization. </p>
+
+<p>It is good practice to use the Android resource framework to separate the
+localized aspects of your application as much as possible from the core Java
+functionality:</p>
+
+<ul>
+ <li>You can put most or all of the <em>contents</em> of your application's
+user interface into resource files, as described in this document and in <a
+href="{@docRoot}guide/topics/resources/providing-resources.html">Providing Resources</a>.</li>
+ <li>The <em>behavior</em> of the user interface, on the other hand, is driven
+by your Java code.
+ For example, if users input data that needs to be formatted or sorted
+differently depending on locale, then you would use Java to handle the data
+programmatically. This document does not cover how to localize your Java code.
+</li>
+</ul>
+
+<p>For a short guide to localizing strings in your app, see the training lesson, <a
+href="{@docRoot}training/basics/supporting-devices/languages.html">Supporting Different Languages</a>. </p>
+
+
+<h2 id="resource-switching">Overview: Resource-Switching in Android</h2>
+
+<p>Resources are text strings, layouts, sounds, graphics, and any other static
+data that your Android application needs. An application can include multiple
+sets of resources, each customized for a different device configuration. When a
+user runs the application, Android automatically selects and loads the
+resources that best match the device.</p>
+
+<p>(This document focuses on localization and locale. For a complete description
+of resource-switching and all the types of configurations that you can
+specify — screen orientation, touchscreen type, and so on — see <a
+href="{@docRoot}guide/topics/resources/providing-resources.html#AlternativeResources">Providing
+Alternative Resources</a>.)</p>
+
+<table border="0" cellspacing="0" cellpadding="0">
+ <tr border="0">
+ <td width="180" style="border: 0pt none ;"><p class="special-note">
+ <strong>When you write your application:</strong>
+ <br><br>
+ You create a set of default resources, plus alternatives to be used in
+ different locales.</p></td>
+ <td style="border: 0pt none; padding:0">
+ <p style="border:0; padding:0"><img src="../../../images/resources/right-arrow.png" alt="right-arrow"
+ width="51" height="17"></p></td>
+ <td width="180" style="border: 0pt none ;"><p class="special-note">
+ <strong>When a user runs your application:</strong>
+ <br><br>The Android system selects which resources to load, based on the
+ device's locale.</p></td>
+ </tr>
+</table>
+
+<p>When you write your application, you create default and alternative resources
+for your application to use. To create resources, you place files within
+specially named subdirectories of the project's <code>res/</code> directory.
+</p>
+
+
+
+<h3 id="defaults-r-important">Why Default Resources Are Important</h3>
+
+<p>Whenever the application runs in a locale for which you have not provided
+locale-specific text, Android will load the default strings from
+<code>res/values/strings.xml</code>. If this default file is absent, or if it
+is missing a string that your application needs, then your application will not run
+and will show an error.
+The example below illustrates what can happen when the default text file is incomplete. </p>
+
+<p><em>Example:</em>
+<p>An application's Java code refers to just two strings, <code>text_a</code> and
+ <code>text_b</code>. This application includes a localized resource file
+ (<code>res/values-en/strings.xml</code>) that defines <code>text_a</code> and
+ <code>text_b</code> in English. This application also includes a default
+ resource file (<code>res/values/strings.xml</code>) that includes a
+definition for <code>text_a</code>, but not for <code>text_b</code>:
+<ul>
+ <li>This application might compile without a problem. An IDE such as Eclipse
+ will not highlight any errors if a resource is missing.</li>
+ <li>When this application is launched on a device with locale set to English,
+ the application might run without a problem, because
+ <code>res/values-en/strings.xml</code> contains both of the needed text
+ strings.</li>
+ <li>However, <strong>the user will see an error message and a Force Close
+ button</strong> when this application is launched on a device set to a
+ language other than English. The application will not load.</li>
+</ul>
+
+
+<p>To prevent this situation, make sure that a <code>res/values/strings.xml</code>
+ file exists and that it defines every needed string. The situation applies to
+ all types of resources, not just strings: You
+ need to create a set of default resource files containing all
+ the resources that your application calls upon — layouts, drawables,
+ animations, etc. For information about testing, see <a href="#test-for-default">
+ Testing for Default Resources</a>.</p>
+
+<h2 id="using-framework">Using Resources for Localization</h2>
+
+<h3 id="creating-defaults">How to Create Default Resources</h3>
+
+<p>Put the application's default text in
+a file with the following location and name:</p>
+<p><code> res/values/strings.xml</code> (required directory)</p>
+
+<p>The text strings in <code>res/values/strings.xml</code> should use the
+default language, which is the language that you expect most of your application's users to
+speak. </p>
+
+<p>The default resource set must also include any default drawables and layouts,
+ and can include other types of resources such as animations.
+<br>
+ <code> res/drawable/</code>(required directory holding at least
+ one graphic file, for the application's icon on Google Play)<br>
+ <code> res/layout/</code> (required directory holding an XML
+ file that defines the default layout)<br>
+ <code> res/anim/</code> (required if you have any
+ <code>res/anim-<em><qualifiers></em></code> folders)<br>
+ <code> res/xml/</code> (required if you have any
+ <code>res/xml-<em><qualifiers></em></code> folders)<br>
+ <code> res/raw/</code> (required if you have any
+ <code>res/raw-<em><qualifiers></em></code> folders)
+</p>
+
+<p class="note"><strong>Tip:</strong> In your code, examine each reference to
+ an Android resource. Make sure that a default resource is defined for each
+ one. Also make sure that the default string file is complete: A <em>
+ localized</em> string file can contain a subset of the strings, but the
+ <em>default</em> string file must contain them all.
+</p>
+
+<h3 id="creating-alternatives">How to Create Alternative Resources</h3>
+
+<p>A large part of localizing an application is providing alternative text for
+different languages. In some cases you will also provide alternative graphics,
+sounds, layouts, and other locale-specific resources. </p>
+
+<p>An application can specify many <code>res/<em><qualifiers></em>/</code>
+directories, each with different qualifiers. To create an alternative resource for
+a different locale, you use a qualifier that specifies a language or a
+language-region combination. (The name of a resource directory must conform
+to the naming scheme described in
+<a href="{@docRoot}guide/topics/resources/providing-resources.html#AlternativeResources">Providing
+Alternative Resources</a>,
+or else it will not compile.)</p>
+
+<p><em>Example:</em></p>
+
+<p>Suppose that your application's default language is English. Suppose also
+that you want to localize all the text in your application to French, and most
+of the text in your application (everything except the application's title) to
+Japanese. In this case, you could create three alternative <code>strings.xml</code>
+files, each stored in a locale-specific resource directory:</p>
+
+<ol>
+ <li><code>res/values/strings.xml</code><br>
+ Contains English text for all the strings that the application uses,
+including text for a string named <code>title</code>.</li>
+ <li><code>res/values-fr/strings.xml</code><br>
+ Contain French text for all the strings, including <code>title</code>.</li>
+ <li><code>res/values-ja/strings.xml</code><br>
+ Contain Japanese text for all the strings <em>except</em>
+<code>title</code>.<br>
+ <code></code></li>
+</ol>
+
+<p>If your Java code refers to <code>R.string.title</code>, here is what will
+happen at runtime:</p>
+
+<ul>
+ <li>If the device is set to any language other than French, Android will load
+<code>title</code> from the <code>res/values/strings.xml</code> file.</li>
+ <li>If the device is set to French, Android will load <code>title</code> from
+the <code>res/values-fr/strings.xml</code> file.</li>
+</ul>
+
+<p>Notice that if the device is set to Japanese, Android will look for
+<code>title</code> in the <code>res/values-ja/strings.xml</code> file. But
+because no such string is included in that file, Android will fall back to the
+default, and will load <code>title</code> in English from the
+<code>res/values/strings.xml</code> file. </p>
+
+<h3 id="resource-precedence">Which Resources Take Precedence?</h3>
+
+<p> If multiple resource files match a device's configuration, Android follows a
+set of rules in deciding which file to use. Among the qualifiers that can be
+specified in a resource directory name, <strong>locale almost always takes
+precedence</strong>. </p>
+<p><em>Example:</em></p>
+
+<p>Assume that an application includes a default set of graphics and two other
+sets of graphics, each optimized for a different device setup:</p>
+
+<ul>
+ <li><code>res/drawable/</code><br>
+ Contains
+ default graphics.</li>
+ <li><code>res/drawable-small-land-stylus/</code><br>
+ Contains graphics optimized for use with a device that expects input from a
+ stylus and has a QVGA low-density screen in landscape orientation.</li>
+ <li><code>res/drawable-ja/</code> <br>
+ Contains graphics optimized for use with Japanese.</li>
+</ul>
+
+<p>If the application runs on a device that is configured to use Japanese,
+Android will load graphics from <code>res/drawable-ja/</code>, even if the
+device happens to be one that expects input from a stylus and has a QVGA
+low-density screen in landscape orientation.</p>
+
+<p class="note"><strong>Exception:</strong> The only qualifiers that take
+precedence over locale in the selection process are MCC and MNC (mobile country
+code and mobile network code). </p>
+
+<p><em>Example:</em></p>
+
+<p>Assume that you have the following situation:</p>
+
+<ul>
+ <li>The application code calls for <code>R.string.text_a</code></li>
+ <li>Two relevant resource files are available:
+ <ul>
+ <li><code>res/values-mcc404/strings.xml</code>, which includes
+<code>text_a</code> in the application's default language, in this case
+English.</li>
+ <li><code>res/values-hi/strings.xml</code>, which includes
+<code>text_a</code> in Hindi.</li>
+ </ul>
+ </li>
+ <li>The application is running on a device that has the following
+configuration:
+ <ul>
+ <li>The SIM card is connected to a mobile network in India (MCC 404).</li>
+ <li>The language is set to Hindi (<code>hi</code>).</li>
+ </ul>
+ </li>
+</ul>
+
+<p>Android will load <code>text_a</code> from
+<code>res/values-mcc404/strings.xml</code> (in English), even if the device is
+configured for Hindi. That is because in the resource-selection process, Android
+will prefer an MCC match over a language match. </p>
+
+<p>The selection process is not always as straightforward as these examples
+suggest. Please read <a
+href="{@docRoot}guide/topics/resources/providing-resources.html#BestMatch">How Android Finds
+the Best-matching Resource</a> for a more nuanced description of the
+process. All the qualifiers are described and listed in order of
+precedence in <a
+href="{@docRoot}guide/topics/resources/providing-resources.html#table2">Table 2 of Providing
+Alternative Resources</a>.</p>
+
+<h3 id="referring-to-resources">Referring to Resources in Java</h3>
+
+<p>In your application's Java code, you refer to resources using the syntax
+<code>R.<em>resource_type</em>.<em>resource_name</em></code> or
+<code>android.R.<em>resource_type</em>.<em>resource_name</em></code><em>.</em>
+For more about this, see <a
+href="{@docRoot}guide/topics/resources/accessing-resources.html">Accessing Resources</a>.</p>
+
+<h2 id="checklist">Localization Checklist</h2>
+
+<p>For a complete overview of the process of localizing and distributing an Android application,
+see the <a href="{@docRoot}distribute/tools/localization-checklist.html">Localization
+Checklist</a> document.</p>
+
+<h2 id="strategies">Localization Tips</h2>
+
+<h4 id="failing2">Design your application to work in any locale</h4>
+
+<p>You cannot assume anything about the device on which a user will
+run your application. The device might have hardware that you were not
+anticipating, or it might be set to a locale that you did not plan for or that
+you cannot test. Design your application so that it will function normally or fail gracefully no
+matter what device it runs on.</p>
+
+<p class="note"><strong>Important:</strong> Make sure that your application
+includes a full set of default resources.</p> <p>Make sure to include
+<code>res/drawable/</code> and a <code>res/values/</code> folders (without any
+additional modifiers in the folder names) that contain all the images and text
+that your application will need. </p>
+
+<p>If an application is missing even one default resource, it will not run on a
+ device that is set to an unsupported locale. For example, the
+ <code>res/values/strings.xml</code> default file might lack one string that
+ the application needs: When the application runs in an unsupported locale and
+ attempts to load <code>res/values/strings.xml</code>, the user will see an
+ error message and a Force Close button. An IDE such as Eclipse will not
+ highlight this kind of error, and you will not see the problem when you
+ test the application on a device or emulator that is set to a supported locale.</p>
+
+<p>For more information, see <a href="#test-for-default">Testing for Default Resources</a>.</p>
+
+<h4>Design a flexible layout</h4>
+
+<p> If you need to rearrange your layout to fit a certain language (for example
+German with its long words), you can create an alternative layout for that
+language (for example <code>res/layout-de/main.xml</code>). However, doing this
+can make your application harder to maintain. It is better to create a single
+layout that is more flexible.</p>
+
+<p>Another typical situation is a language that requires something different in
+its layout. For example, you might have a contact form that should include two
+name fields when the application runs in Japanese, but three name fields when
+the application runs in some other language. You could handle this in either of
+two ways:</p>
+
+<ul>
+ <li>Create one layout with a field that you can programmatically enable or
+disable, based on the language, or</li>
+ <li>Have the main layout include another layout that includes the changeable
+field. The second layout can have different configurations for different
+languages.</li>
+</ul>
+
+<h4>Avoid creating more resource files and text strings than you need</h4>
+
+<p>You probably do not need to create a locale-specific
+alternative for every resource in your application. For example, the layout
+defined in the <code>res/layout/main.xml</code> file might work in any locale,
+in which case there would be no need to create any alternative layout files.
+</p>
+
+<p>Also, you might not need to create alternative text for every
+string. For example, assume the following:</p>
+
+<ul>
+ <li>Your application's default language is American
+English. Every string that the application uses is defined, using American
+English spellings, in <code>res/values/strings.xml</code>. </li>
+
+ <li>For a few important phrases, you want to provide
+British English spelling. You want these alternative strings to be used when your
+application runs on a device in the United Kingdom. </li>
+</ul>
+
+<p>To do this, you could create a small file called
+<code>res/values-en-rGB/strings.xml</code> that includes only the strings that
+should be different when the application runs in the U.K. For all the rest of
+the strings, the application will fall back to the defaults and use what is
+defined in <code>res/values/strings.xml</code>.</p>
+
+<h4>Use the Android Context object for manual locale lookup</h4>
+
+<p>You can look up the locale using the {@link android.content.Context} object
+that Android makes available:</p>
+
+<pre>String locale = context.getResources().getConfiguration().locale.getDisplayName();</pre>
+
+<h2 id="testing">Testing Localized Applications</h2>
+
+<h3 id="device">Testing on a Device</h3>
+<p>Keep in mind that the device you are testing may be significantly different from
+ the devices available to consumers in other geographies. The locales available
+ on your device may differ from those available on other devices. Also, the
+ resolution and density of the device screen may differ, which could affect
+ the display of strings and drawables in your UI.</p>
+
+<p>To change the locale or language on a device, use the Settings application.</p>
+
+<h3 id="emulator">Testing on an Emulator</h3>
+
+<p>For details about using the emulator, see See <a
+href="{@docRoot}tools/help/emulator.html">Android Emulator</a>.</p>
+<h4>Creating and using a custom locale</h4>
+
+<p>A "custom" locale is a language/region combination that the Android
+system image does not explicitly support. (For a list of supported locales in
+Android platforms see the Version Notes in the <a
+href="{@docRoot}sdk/index.html">SDK</a> tab). You can test
+how your application will run in a custom locale by creating a custom locale in
+the emulator. There are two ways to do this:</p>
+
+<ul>
+ <li>Use the Custom Locale application, which is accessible from the
+Application tab. (After you create a custom locale, switch to it by
+pressing and holding the locale name.)</li>
+ <li>Change to a custom locale from the adb shell, as described below.</li>
+</ul>
+
+<p>When you set the emulator to a locale that is not available in the Android
+system image, the system itself will display in its default language. Your
+application, however, should localize properly.</p>
+
+<h4>Changing the emulator locale from the adb shell</h4>
+
+<p>To change the locale in the emulator by using the adb shell. </p>
+
+<ol>
+ <li>Pick the locale you want to test and determine its BCP-47 language tag, for
+example, Canadian French would be <code>fr-CA</code>.<br>
+ </li>
+ <li>Launch an emulator.</li>
+ <li>From a command-line shell on the host computer, run the following
+command:<br>
+ <code>adb shell</code><br>
+ or if you have a device attached, specify that you want the emulator by adding
+the <code>-e</code> option:<br>
+ <code>adb -e shell</code></li>
+ <li>At the adb shell prompt (<code>#</code>), run this command: <br>
+ <code>setprop persist.sys.locale [<em>BCP-47 language tag</em>];stop;sleep 5;start <br>
+ </code>Replace bracketed sections with the appropriate codes from Step
+1.</li>
+</ol>
+
+<p>For instance, to test in Canadian French:</p>
+
+<p><code>setprop persist.sys.locale fr-CA;stop;sleep 5;start </code></p>
+
+<p>This will cause the emulator to restart. (It will look like a full reboot,
+but it is not.) Once the Home screen appears again, re-launch your application (for
+example, click the Run icon in Eclipse), and the application will launch with
+the new locale. </p>
+
+<h3 id="test-for-default">Testing for Default Resources</h3>
+<p>Here's how to test whether an application includes every string resource that it needs: </p>
+<ol><li>Set the emulator or device to a language that your application does not
+ support. For example, if the application has French strings in
+ <code>res/values-fr/</code> but does not have any Spanish strings in
+ <code>res/values-es/</code>, then set the emulator's locale to Spanish.
+ (You can use the Custom Locale application to set the emulator to an
+ unsupported locale.)</li>
+ <li>Run the application.</li>
+<li>If the application shows an error message and a Force Close button, it might
+ be looking for a string that is not available. Make sure that your
+ <code>res/values/strings.xml</code> file includes a definition for
+ every string that the application uses.</li>
+</ol>
+</p>
+
+<p>If the test is successful, repeat it for other types of
+ configurations. For example, if the application has a layout file called
+ <code>res/layout-land/main.xml</code> but does not contain a file called
+ <code>res/layout-port/main.xml</code>, then set the emulator or device to
+ portrait orientation and see if the application will run.
+
+
+
diff --git a/docs/overview-ext.html b/docs/overview-ext.html
index 5720245..f80d629 100644
--- a/docs/overview-ext.html
+++ b/docs/overview-ext.html
@@ -1,8 +1,8 @@
-<body>
-Some random libraries that we've imported:
-<ul>
- <li>GData</li>
- <li>Apache commons HTTPClient</li>
- <li>A sax parser</li>
-</ul>
-</body>
+<body>
+Some random libraries that we've imported:
+<ul>
+ <li>GData</li>
+ <li>Apache commons HTTPClient</li>
+ <li>A sax parser</li>
+</ul>
+</body>
diff --git a/graphics/java/android/graphics/FontListParser.java b/graphics/java/android/graphics/FontListParser.java
index 8f7c6a62..7871aa8 100644
--- a/graphics/java/android/graphics/FontListParser.java
+++ b/graphics/java/android/graphics/FontListParser.java
@@ -179,10 +179,10 @@
int tag = 0;
String tagStr = parser.getAttributeValue(null, "tag");
if (tagStr != null && TAG_PATTERN.matcher(tagStr).matches()) {
- tag = tagStr.charAt(0) << 24 +
- tagStr.charAt(1) << 16 +
- tagStr.charAt(2) << 8 +
- tagStr.charAt(3);
+ tag = (tagStr.charAt(0) << 24) +
+ (tagStr.charAt(1) << 16) +
+ (tagStr.charAt(2) << 8) +
+ (tagStr.charAt(3) );
} else {
throw new XmlPullParserException("Invalid tag attribute value.", parser, null);
}
diff --git a/graphics/java/android/graphics/Outline.java b/graphics/java/android/graphics/Outline.java
index 3973f2f..aa81b91 100644
--- a/graphics/java/android/graphics/Outline.java
+++ b/graphics/java/android/graphics/Outline.java
@@ -37,22 +37,26 @@
public final class Outline {
private static final float RADIUS_UNDEFINED = Float.NEGATIVE_INFINITY;
- private static final int MODE_EMPTY = 0;
- private static final int MODE_RECT = 1;
- private static final int MODE_CONVEX_PATH = 2;
+ /** @hide */
+ public static final int MODE_EMPTY = 0;
+ /** @hide */
+ public static final int MODE_ROUND_RECT = 1;
+ /** @hide */
+ public static final int MODE_CONVEX_PATH = 2;
/** @hide */
@Retention(RetentionPolicy.SOURCE)
@IntDef(flag = false,
value = {
MODE_EMPTY,
- MODE_RECT,
+ MODE_ROUND_RECT,
MODE_CONVEX_PATH,
})
public @interface Mode {}
+ /** @hide */
@Mode
- private int mMode = MODE_EMPTY;
+ public int mMode = MODE_EMPTY;
/** @hide */
public final Path mPath = new Path();
@@ -176,7 +180,7 @@
return;
}
- mMode = MODE_RECT;
+ mMode = MODE_ROUND_RECT;
mRect.set(left, top, right, bottom);
mRadius = radius;
mPath.rewind();
@@ -199,7 +203,7 @@
* bounds, or {@code false} if no outline bounds are set
*/
public boolean getRect(@NonNull Rect outRect) {
- if (mMode != MODE_RECT) {
+ if (mMode != MODE_ROUND_RECT) {
return false;
}
outRect.set(mRect);
@@ -270,7 +274,7 @@
* Offsets the Outline by (dx,dy)
*/
public void offset(int dx, int dy) {
- if (mMode == MODE_RECT) {
+ if (mMode == MODE_ROUND_RECT) {
mRect.offset(dx, dy);
} else if (mMode == MODE_CONVEX_PATH) {
mPath.offset(dx, dy);
diff --git a/graphics/java/android/graphics/Paint.java b/graphics/java/android/graphics/Paint.java
index 291fdc4..0dae796 100644
--- a/graphics/java/android/graphics/Paint.java
+++ b/graphics/java/android/graphics/Paint.java
@@ -1494,9 +1494,14 @@
}
/**
- * Get font feature settings. Default is null.
+ * Returns the font feature settings. The format is the same as the CSS
+ * font-feature-settings attribute:
+ * <a href="http://dev.w3.org/csswg/css-fonts/#propdef-font-feature-settings">
+ * http://dev.w3.org/csswg/css-fonts/#propdef-font-feature-settings</a>
*
- * @return the paint's currently set font feature settings.
+ * @return the paint's currently set font feature settings. Default is null.
+ *
+ * @see #setFontFeatureSettings(String)
*/
public String getFontFeatureSettings() {
return mFontFeatureSettings;
@@ -1506,7 +1511,10 @@
* Set font feature settings.
*
* The format is the same as the CSS font-feature-settings attribute:
- * http://dev.w3.org/csswg/css-fonts/#propdef-font-feature-settings
+ * <a href="http://dev.w3.org/csswg/css-fonts/#propdef-font-feature-settings">
+ * http://dev.w3.org/csswg/css-fonts/#propdef-font-feature-settings</a>
+ *
+ * @see #getFontFeatureSettings()
*
* @param settings the font feature settings string to use, may be null.
*/
diff --git a/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
index 46a0f43..35385eb 100644
--- a/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
+++ b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
@@ -1416,6 +1416,9 @@
Log.d(LOGTAG, "on finished called from native");
}
mStarted = false;
+ // Invalidate in the end of the animation to make sure the data in
+ // RT thread is synced back to UI thread.
+ invalidateOwningView();
if (mListener != null) {
mListener.onAnimationEnd(null);
}
diff --git a/graphics/java/android/graphics/drawable/Drawable.java b/graphics/java/android/graphics/drawable/Drawable.java
index 3915984..4f600b4 100644
--- a/graphics/java/android/graphics/drawable/Drawable.java
+++ b/graphics/java/android/graphics/drawable/Drawable.java
@@ -1198,6 +1198,8 @@
/**
* Inflate this Drawable from an XML resource optionally styled by a theme.
+ * This can't be called more than once for each Drawable. Note that framework may have called
+ * this once to create the Drawable instance from XML resource.
*
* @param r Resources used to resolve attribute values
* @param parser XML parser from which to inflate this Drawable
diff --git a/keystore/java/android/security/IKeyChainService.aidl b/keystore/java/android/security/IKeyChainService.aidl
index cfcb4e0..deea972 100644
--- a/keystore/java/android/security/IKeyChainService.aidl
+++ b/keystore/java/android/security/IKeyChainService.aidl
@@ -27,12 +27,13 @@
// APIs used by KeyChain
String requestPrivateKey(String alias);
byte[] getCertificate(String alias);
+ byte[] getCaCertificates(String alias);
// APIs used by CertInstaller
void installCaCertificate(in byte[] caCertificate);
// APIs used by DevicePolicyManager
- boolean installKeyPair(in byte[] privateKey, in byte[] userCert, String alias);
+ boolean installKeyPair(in byte[] privateKey, in byte[] userCert, in byte[] certChain, String alias);
boolean removeKeyPair(String alias);
// APIs used by Settings
diff --git a/keystore/java/android/security/KeyChain.java b/keystore/java/android/security/KeyChain.java
index 0886487..cce58c2 100644
--- a/keystore/java/android/security/KeyChain.java
+++ b/keystore/java/android/security/KeyChain.java
@@ -42,6 +42,8 @@
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Collection;
import java.util.List;
import java.util.Locale;
import java.util.concurrent.BlockingQueue;
@@ -389,7 +391,12 @@
/**
* Returns the {@code X509Certificate} chain for the requested
- * alias, or null if no there is no result.
+ * alias, or null if there is no result.
+ * <p>
+ * <strong>Note:</strong> If a certificate chain was explicitly specified when the alias was
+ * installed, this method will return that chain. If only the client certificate was specified
+ * at the installation time, this method will try to build a certificate chain using all
+ * available trust anchors (preinstalled and user-added).
*
* <p> This method may block while waiting for a connection to another process, and must never
* be called from the main thread.
@@ -413,11 +420,31 @@
if (certificateBytes == null) {
return null;
}
-
- TrustedCertificateStore store = new TrustedCertificateStore();
- List<X509Certificate> chain = store
- .getCertificateChain(toCertificate(certificateBytes));
- return chain.toArray(new X509Certificate[chain.size()]);
+ X509Certificate leafCert = toCertificate(certificateBytes);
+ final byte[] certChainBytes = keyChainService.getCaCertificates(alias);
+ // If the keypair is installed with a certificate chain by either
+ // DevicePolicyManager.installKeyPair or CertInstaller, return that chain.
+ if (certChainBytes != null && certChainBytes.length != 0) {
+ Collection<X509Certificate> chain = toCertificates(certChainBytes);
+ ArrayList<X509Certificate> fullChain = new ArrayList<>(chain.size() + 1);
+ fullChain.add(leafCert);
+ fullChain.addAll(chain);
+ return fullChain.toArray(new X509Certificate[fullChain.size()]);
+ } else {
+ // If there isn't a certificate chain, either due to a pre-existing keypair
+ // installed before N, or no chain is explicitly installed under the new logic,
+ // fall back to old behavior of constructing the chain from trusted credentials.
+ //
+ // This logic exists to maintain old behaviour for already installed keypair, at
+ // the cost of potentially returning extra certificate chain for new clients who
+ // explicitly installed only the client certificate without a chain. The latter
+ // case is actually no different from pre-N behaviour of getCertificateChain(),
+ // in that sense this change introduces no regression. Besides the returned chain
+ // is still valid so the consumer of the chain should have no problem verifying it.
+ TrustedCertificateStore store = new TrustedCertificateStore();
+ List<X509Certificate> chain = store.getCertificateChain(leafCert);
+ return chain.toArray(new X509Certificate[chain.size()]);
+ }
} catch (CertificateException e) {
throw new KeyChainException(e);
} catch (RemoteException e) {
@@ -486,6 +513,21 @@
}
}
+ /** @hide */
+ @NonNull
+ public static Collection<X509Certificate> toCertificates(@NonNull byte[] bytes) {
+ if (bytes == null) {
+ throw new IllegalArgumentException("bytes == null");
+ }
+ try {
+ CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
+ return (Collection<X509Certificate>) certFactory.generateCertificates(
+ new ByteArrayInputStream(bytes));
+ } catch (CertificateException e) {
+ throw new AssertionError(e);
+ }
+ }
+
/**
* @hide for reuse by CertInstaller and Settings.
* @see KeyChain#bind
diff --git a/libs/androidfw/ResourceTypes.cpp b/libs/androidfw/ResourceTypes.cpp
index 52fe973..1ccc59a 100644
--- a/libs/androidfw/ResourceTypes.cpp
+++ b/libs/androidfw/ResourceTypes.cpp
@@ -3935,7 +3935,9 @@
if (Res_GETPACKAGE(resID)+1 == 0) {
ALOGW("No package identifier when getting name for resource number 0x%08x", resID);
} else {
+#ifndef STATIC_ANDROIDFW_FOR_TOOLS
ALOGW("No known package when getting name for resource number 0x%08x", resID);
+#endif
}
return false;
}
diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk
index 516591b..be816f7 100644
--- a/libs/hwui/Android.mk
+++ b/libs/hwui/Android.mk
@@ -252,6 +252,7 @@
tests/unit/LinearAllocatorTests.cpp \
tests/unit/MatrixTests.cpp \
tests/unit/OffscreenBufferPoolTests.cpp \
+ tests/unit/RenderNodeTests.cpp \
tests/unit/SkiaBehaviorTests.cpp \
tests/unit/StringUtilsTests.cpp \
tests/unit/TextDropShadowCacheTests.cpp \
@@ -266,7 +267,8 @@
tests/unit/FrameBuilderTests.cpp \
tests/unit/LeakCheckTests.cpp \
tests/unit/OpDumperTests.cpp \
- tests/unit/RecordingCanvasTests.cpp
+ tests/unit/RecordingCanvasTests.cpp \
+ tests/unit/SkiaCanvasTests.cpp
endif
include $(LOCAL_PATH)/hwui_static_deps.mk
@@ -321,6 +323,7 @@
$(hwui_test_common_src_files) \
tests/microbench/main.cpp \
tests/microbench/DisplayListCanvasBench.cpp \
+ tests/microbench/FontBench.cpp \
tests/microbench/LinearAllocatorBench.cpp \
tests/microbench/PathParserBench.cpp \
tests/microbench/ShadowBench.cpp \
diff --git a/libs/hwui/BakedOpDispatcher.cpp b/libs/hwui/BakedOpDispatcher.cpp
index ea4f4eb..f43bf86 100644
--- a/libs/hwui/BakedOpDispatcher.cpp
+++ b/libs/hwui/BakedOpDispatcher.cpp
@@ -195,7 +195,7 @@
}
static void renderTextShadow(BakedOpRenderer& renderer, FontRenderer& fontRenderer,
- const TextOp& op, const BakedOpState& state) {
+ const TextOp& op, const BakedOpState& textOpState) {
renderer.caches().textureState().activateTexture(0);
PaintUtils::TextShadow textShadow;
@@ -216,13 +216,41 @@
Glop glop;
GlopBuilder(renderer.renderState(), renderer.caches(), &glop)
- .setRoundRectClipState(state.roundRectClipState)
+ .setRoundRectClipState(textOpState.roundRectClipState)
.setMeshTexturedUnitQuad(nullptr)
- .setFillShadowTexturePaint(*texture, textShadow.color, *op.paint, state.alpha)
- .setTransform(state.computedState.transform, TransformFlags::None)
+ .setFillShadowTexturePaint(*texture, textShadow.color, *op.paint, textOpState.alpha)
+ .setTransform(textOpState.computedState.transform, TransformFlags::None)
.setModelViewMapUnitToRect(Rect(sx, sy, sx + texture->width(), sy + texture->height()))
.build();
- renderer.renderGlop(state, glop);
+
+ // Compute damage bounds and clip (since may differ from those in textOpState).
+ // Bounds should be same as text op, but with dx/dy offset and radius outset
+ // applied in local space.
+ auto& transform = textOpState.computedState.transform;
+ Rect shadowBounds = op.unmappedBounds; // STROKE
+ const bool expandForStroke = op.paint->getStyle() != SkPaint::kFill_Style;
+ if (expandForStroke) {
+ shadowBounds.outset(op.paint->getStrokeWidth() * 0.5f);
+ }
+ shadowBounds.translate(textShadow.dx, textShadow.dy);
+ shadowBounds.outset(textShadow.radius, textShadow.radius);
+ transform.mapRect(shadowBounds);
+ if (CC_UNLIKELY(expandForStroke &&
+ (!transform.isPureTranslate() || op.paint->getStrokeWidth() < 1.0f))) {
+ shadowBounds.outset(0.5f);
+ }
+
+ auto clipState = textOpState.computedState.clipState;
+ if (clipState->mode != ClipMode::Rectangle
+ || !clipState->rect.contains(shadowBounds)) {
+ // need clip, so pass it and clip bounds
+ shadowBounds.doIntersect(clipState->rect);
+ } else {
+ // don't need clip, ignore
+ clipState = nullptr;
+ }
+
+ renderer.renderGlop(&shadowBounds, clipState, glop);
}
enum class TextRenderType {
diff --git a/libs/hwui/BakedOpState.cpp b/libs/hwui/BakedOpState.cpp
index 85903654..b70d586 100644
--- a/libs/hwui/BakedOpState.cpp
+++ b/libs/hwui/BakedOpState.cpp
@@ -108,5 +108,63 @@
clippedBounds.doIntersect(clipRect->rect);
}
+BakedOpState* BakedOpState::tryConstruct(LinearAllocator& allocator,
+ Snapshot& snapshot, const RecordedOp& recordedOp) {
+ if (CC_UNLIKELY(snapshot.getRenderTargetClip().isEmpty())) return nullptr;
+ BakedOpState* bakedState = allocator.create_trivial<BakedOpState>(
+ allocator, snapshot, recordedOp, false);
+ if (bakedState->computedState.clippedBounds.isEmpty()) {
+ // bounds are empty, so op is rejected
+ allocator.rewindIfLastAlloc(bakedState);
+ return nullptr;
+ }
+ return bakedState;
+}
+
+BakedOpState* BakedOpState::tryConstructUnbounded(LinearAllocator& allocator,
+ Snapshot& snapshot, const RecordedOp& recordedOp) {
+ if (CC_UNLIKELY(snapshot.getRenderTargetClip().isEmpty())) return nullptr;
+ return allocator.create_trivial<BakedOpState>(allocator, snapshot, recordedOp);
+}
+
+BakedOpState* BakedOpState::tryStrokeableOpConstruct(LinearAllocator& allocator,
+ Snapshot& snapshot, const RecordedOp& recordedOp, StrokeBehavior strokeBehavior) {
+ if (CC_UNLIKELY(snapshot.getRenderTargetClip().isEmpty())) return nullptr;
+ bool expandForStroke = (strokeBehavior == StrokeBehavior::StyleDefined)
+ ? (recordedOp.paint && recordedOp.paint->getStyle() != SkPaint::kFill_Style)
+ : true;
+
+ BakedOpState* bakedState = allocator.create_trivial<BakedOpState>(
+ allocator, snapshot, recordedOp, expandForStroke);
+ if (bakedState->computedState.clippedBounds.isEmpty()) {
+ // bounds are empty, so op is rejected
+ // NOTE: this won't succeed if a clip was allocated
+ allocator.rewindIfLastAlloc(bakedState);
+ return nullptr;
+ }
+ return bakedState;
+}
+
+BakedOpState* BakedOpState::tryShadowOpConstruct(LinearAllocator& allocator,
+ Snapshot& snapshot, const ShadowOp* shadowOpPtr) {
+ if (CC_UNLIKELY(snapshot.getRenderTargetClip().isEmpty())) return nullptr;
+
+ // clip isn't empty, so construct the op
+ return allocator.create_trivial<BakedOpState>(allocator, snapshot, shadowOpPtr);
+}
+
+BakedOpState* BakedOpState::directConstruct(LinearAllocator& allocator,
+ const ClipRect* clip, const Rect& dstRect, const RecordedOp& recordedOp) {
+ return allocator.create_trivial<BakedOpState>(clip, dstRect, recordedOp);
+}
+
+void BakedOpState::setupOpacity(const SkPaint* paint) {
+ computedState.opaqueOverClippedBounds = computedState.transform.isSimple()
+ && computedState.clipState->mode == ClipMode::Rectangle
+ && MathUtils::areEqual(alpha, 1.0f)
+ && !roundRectClipState
+ && PaintUtils::isOpaquePaint(paint);
+}
+
} // namespace uirenderer
} // namespace android
diff --git a/libs/hwui/BakedOpState.h b/libs/hwui/BakedOpState.h
index 4e3cb8a..e1441fc 100644
--- a/libs/hwui/BakedOpState.h
+++ b/libs/hwui/BakedOpState.h
@@ -93,6 +93,7 @@
Rect clippedBounds;
int clipSideFlags = 0;
const SkPath* localProjectionPathMask = nullptr;
+ bool opaqueOverClippedBounds = false;
};
/**
@@ -103,23 +104,10 @@
class BakedOpState {
public:
static BakedOpState* tryConstruct(LinearAllocator& allocator,
- Snapshot& snapshot, const RecordedOp& recordedOp) {
- if (CC_UNLIKELY(snapshot.getRenderTargetClip().isEmpty())) return nullptr;
- BakedOpState* bakedState = allocator.create_trivial<BakedOpState>(
- allocator, snapshot, recordedOp, false);
- if (bakedState->computedState.clippedBounds.isEmpty()) {
- // bounds are empty, so op is rejected
- allocator.rewindIfLastAlloc(bakedState);
- return nullptr;
- }
- return bakedState;
- }
+ Snapshot& snapshot, const RecordedOp& recordedOp);
static BakedOpState* tryConstructUnbounded(LinearAllocator& allocator,
- Snapshot& snapshot, const RecordedOp& recordedOp) {
- if (CC_UNLIKELY(snapshot.getRenderTargetClip().isEmpty())) return nullptr;
- return allocator.create_trivial<BakedOpState>(allocator, snapshot, recordedOp);
- }
+ Snapshot& snapshot, const RecordedOp& recordedOp);
enum class StrokeBehavior {
// stroking is forced, regardless of style on paint (such as for lines)
@@ -129,35 +117,16 @@
};
static BakedOpState* tryStrokeableOpConstruct(LinearAllocator& allocator,
- Snapshot& snapshot, const RecordedOp& recordedOp, StrokeBehavior strokeBehavior) {
- if (CC_UNLIKELY(snapshot.getRenderTargetClip().isEmpty())) return nullptr;
- bool expandForStroke = (strokeBehavior == StrokeBehavior::StyleDefined)
- ? (recordedOp.paint && recordedOp.paint->getStyle() != SkPaint::kFill_Style)
- : true;
-
- BakedOpState* bakedState = allocator.create_trivial<BakedOpState>(
- allocator, snapshot, recordedOp, expandForStroke);
- if (bakedState->computedState.clippedBounds.isEmpty()) {
- // bounds are empty, so op is rejected
- // NOTE: this won't succeed if a clip was allocated
- allocator.rewindIfLastAlloc(bakedState);
- return nullptr;
- }
- return bakedState;
- }
+ Snapshot& snapshot, const RecordedOp& recordedOp, StrokeBehavior strokeBehavior);
static BakedOpState* tryShadowOpConstruct(LinearAllocator& allocator,
- Snapshot& snapshot, const ShadowOp* shadowOpPtr) {
- if (CC_UNLIKELY(snapshot.getRenderTargetClip().isEmpty())) return nullptr;
-
- // clip isn't empty, so construct the op
- return allocator.create_trivial<BakedOpState>(allocator, snapshot, shadowOpPtr);
- }
+ Snapshot& snapshot, const ShadowOp* shadowOpPtr);
static BakedOpState* directConstruct(LinearAllocator& allocator,
- const ClipRect* clip, const Rect& dstRect, const RecordedOp& recordedOp) {
- return allocator.create_trivial<BakedOpState>(clip, dstRect, recordedOp);
- }
+ const ClipRect* clip, const Rect& dstRect, const RecordedOp& recordedOp);
+
+ // Set opaqueOverClippedBounds. If this method isn't called, the op is assumed translucent.
+ void setupOpacity(const SkPaint* paint);
// computed state:
ResolvedRenderState computedState;
diff --git a/libs/hwui/DisplayList.cpp b/libs/hwui/DisplayList.cpp
index 59f0d7c..181b343 100644
--- a/libs/hwui/DisplayList.cpp
+++ b/libs/hwui/DisplayList.cpp
@@ -45,6 +45,7 @@
, regions(stdAllocator)
, referenceHolders(stdAllocator)
, functors(stdAllocator)
+ , pushStagingFunctors(stdAllocator)
, hasDrawOps(false) {
}
diff --git a/libs/hwui/DisplayList.h b/libs/hwui/DisplayList.h
index 60cc7ba..e209e2a 100644
--- a/libs/hwui/DisplayList.h
+++ b/libs/hwui/DisplayList.h
@@ -110,6 +110,16 @@
};
/**
+ * Functor that can be used for objects with data in both UI thread and RT to keep the data
+ * in sync. This functor, when added to DisplayList, will be call during DisplayList sync.
+ */
+struct PushStagingFunctor {
+ PushStagingFunctor() {}
+ virtual ~PushStagingFunctor() {}
+ virtual void operator ()() {}
+};
+
+/**
* Data structure that holds the list of commands used in display list stream
*/
class DisplayList {
@@ -142,6 +152,7 @@
const LsaVector<const SkBitmap*>& getBitmapResources() const { return bitmapResources; }
const LsaVector<Functor*>& getFunctors() const { return functors; }
+ const LsaVector<PushStagingFunctor*>& getPushStagingFunctors() { return pushStagingFunctors; }
size_t addChild(NodeOpType* childOp);
@@ -183,6 +194,11 @@
// List of functors
LsaVector<Functor*> functors;
+ // List of functors that need to be notified of pushStaging. Note that this list gets nothing
+ // but a callback during sync DisplayList, unlike the list of functors defined above, which
+ // gets special treatment exclusive for webview.
+ LsaVector<PushStagingFunctor*> pushStagingFunctors;
+
bool hasDrawOps; // only used if !HWUI_NEW_OPS
void cleanupResources();
diff --git a/libs/hwui/DisplayListCanvas.cpp b/libs/hwui/DisplayListCanvas.cpp
index 2dccf32..c6e92ab 100644
--- a/libs/hwui/DisplayListCanvas.cpp
+++ b/libs/hwui/DisplayListCanvas.cpp
@@ -415,7 +415,8 @@
void DisplayListCanvas::drawVectorDrawable(VectorDrawableRoot* tree) {
mDisplayList->ref(tree);
- addDrawOp(new (alloc()) DrawVectorDrawableOp(tree));
+ mDisplayList->pushStagingFunctors.push_back(tree->getFunctor());
+ addDrawOp(new (alloc()) DrawVectorDrawableOp(tree, tree->stagingProperties()->getBounds()));
}
void DisplayListCanvas::drawGlyphsOnPath(const uint16_t* glyphs, int count,
diff --git a/libs/hwui/DisplayListOp.h b/libs/hwui/DisplayListOp.h
index 516e619..59f073f 100644
--- a/libs/hwui/DisplayListOp.h
+++ b/libs/hwui/DisplayListOp.h
@@ -1110,15 +1110,14 @@
class DrawVectorDrawableOp : public DrawOp {
public:
- DrawVectorDrawableOp(VectorDrawableRoot* tree)
- : DrawOp(nullptr), mTree(tree) {}
+ DrawVectorDrawableOp(VectorDrawableRoot* tree, const SkRect& bounds)
+ : DrawOp(nullptr), mTree(tree), mDst(bounds) {}
virtual void applyDraw(OpenGLRenderer& renderer, Rect& dirty) override {
const SkBitmap& bitmap = mTree->getBitmapUpdateIfDirty();
SkPaint* paint = mTree->getPaint();
- const SkRect bounds = mTree->getBounds();
renderer.drawBitmap(&bitmap, Rect(0, 0, bitmap.width(), bitmap.height()),
- bounds, paint);
+ mDst, paint);
}
virtual void output(int level, uint32_t logFlags) const override {
@@ -1129,6 +1128,7 @@
private:
VectorDrawableRoot* mTree;
+ SkRect mDst;
};
diff --git a/libs/hwui/FrameBuilder.cpp b/libs/hwui/FrameBuilder.cpp
index 0ebb886..0401f2d 100644
--- a/libs/hwui/FrameBuilder.cpp
+++ b/libs/hwui/FrameBuilder.cpp
@@ -37,7 +37,8 @@
const LightGeometry& lightGeometry, const Rect &contentDrawBounds, Caches& caches)
: mCanvasState(*this)
, mCaches(caches)
- , mLightRadius(lightGeometry.radius) {
+ , mLightRadius(lightGeometry.radius)
+ , mDrawFbo0(!nodes.empty()) {
ATRACE_NAME("prepare drawing commands");
mLayerBuilders.reserve(layers.entries().size());
@@ -481,12 +482,17 @@
* Defers an unmergeable, strokeable op, accounting correctly
* for paint's style on the bounds being computed.
*/
-const BakedOpState* FrameBuilder::deferStrokeableOp(const RecordedOp& op, batchid_t batchId,
+BakedOpState* FrameBuilder::deferStrokeableOp(const RecordedOp& op, batchid_t batchId,
BakedOpState::StrokeBehavior strokeBehavior) {
// Note: here we account for stroke when baking the op
BakedOpState* bakedState = BakedOpState::tryStrokeableOpConstruct(
mAllocator, *mCanvasState.writableSnapshot(), op, strokeBehavior);
if (!bakedState) return nullptr; // quick rejected
+
+ if (op.opId == RecordedOpId::RectOp && op.paint->getStyle() != SkPaint::kStroke_Style) {
+ bakedState->setupOpacity(op.paint);
+ }
+
currentLayer().deferUnmergeableOp(mAllocator, bakedState, batchId);
return bakedState;
}
@@ -517,6 +523,10 @@
BakedOpState* bakedState = tryBakeOpState(op);
if (!bakedState) return; // quick rejected
+ if (op.bitmap->isOpaque()) {
+ bakedState->setupOpacity(op.paint);
+ }
+
// Don't merge non-simply transformed or neg scale ops, SET_TEXTURE doesn't handle rotation
// Don't merge A8 bitmaps - the paint's color isn't compared by mergeId, or in
// MergingDrawBatch::canMergeWith()
@@ -699,7 +709,17 @@
void FrameBuilder::deferTextureLayerOp(const TextureLayerOp& op) {
if (CC_UNLIKELY(!op.layer->isRenderable())) return;
- BakedOpState* bakedState = tryBakeOpState(op);
+
+ const TextureLayerOp* textureLayerOp = &op;
+ // Now safe to access transform (which was potentially unready at record time)
+ if (!op.layer->getTransform().isIdentity()) {
+ // non-identity transform present, so 'inject it' into op by copying + replacing matrix
+ Matrix4 combinedMatrix(op.localMatrix);
+ combinedMatrix.multiply(op.layer->getTransform());
+ textureLayerOp = mAllocator.create<TextureLayerOp>(op, combinedMatrix);
+ }
+ BakedOpState* bakedState = tryBakeOpState(*textureLayerOp);
+
if (!bakedState) return; // quick rejected
currentLayer().deferUnmergeableOp(mAllocator, bakedState, OpBatchType::TextureLayer);
}
diff --git a/libs/hwui/FrameBuilder.h b/libs/hwui/FrameBuilder.h
index 0b7a606..e418227 100644
--- a/libs/hwui/FrameBuilder.h
+++ b/libs/hwui/FrameBuilder.h
@@ -137,12 +137,14 @@
}
GL_CHECKPOINT(MODERATE);
- const LayerBuilder& fbo0 = *(mLayerBuilders[0]);
- renderer.startFrame(fbo0.width, fbo0.height, fbo0.repaintRect);
- GL_CHECKPOINT(MODERATE);
- fbo0.replayBakedOpsImpl((void*)&renderer, unmergedReceivers, mergedReceivers);
- GL_CHECKPOINT(MODERATE);
- renderer.endFrame(fbo0.repaintRect);
+ if (CC_LIKELY(mDrawFbo0)) {
+ const LayerBuilder& fbo0 = *(mLayerBuilders[0]);
+ renderer.startFrame(fbo0.width, fbo0.height, fbo0.repaintRect);
+ GL_CHECKPOINT(MODERATE);
+ fbo0.replayBakedOpsImpl((void*)&renderer, unmergedReceivers, mergedReceivers);
+ GL_CHECKPOINT(MODERATE);
+ renderer.endFrame(fbo0.repaintRect);
+ }
}
void dump() const {
@@ -201,7 +203,7 @@
return mAllocator.create<SkPath>();
}
- const BakedOpState* deferStrokeableOp(const RecordedOp& op, batchid_t batchId,
+ BakedOpState* deferStrokeableOp(const RecordedOp& op, batchid_t batchId,
BakedOpState::StrokeBehavior strokeBehavior = BakedOpState::StrokeBehavior::StyleDefined);
/**
@@ -239,6 +241,8 @@
// contains single-frame objects, such as BakedOpStates, LayerBuilders, Batches
LinearAllocator mAllocator;
+
+ const bool mDrawFbo0;
};
}; // namespace uirenderer
diff --git a/libs/hwui/Glop.h b/libs/hwui/Glop.h
index 704bd69..6a96634 100644
--- a/libs/hwui/Glop.h
+++ b/libs/hwui/Glop.h
@@ -163,11 +163,13 @@
GLenum dst;
} blend;
+#if !HWUI_NEW_OPS
/**
* Bounds of the drawing command in layer space. Only mapped into layer
* space once GlopBuilder::build() is called.
*/
Rect bounds; // TODO: remove for HWUI_NEW_OPS
+#endif
/**
* Additional render state to enumerate:
diff --git a/libs/hwui/GlopBuilder.cpp b/libs/hwui/GlopBuilder.cpp
index 2799def..7d4f410 100644
--- a/libs/hwui/GlopBuilder.cpp
+++ b/libs/hwui/GlopBuilder.cpp
@@ -492,7 +492,9 @@
mOutGlop->transform.modelView.loadTranslate(destination.left, destination.top, 0.0f);
mOutGlop->transform.modelView.scale(destination.getWidth(), destination.getHeight(), 1.0f);
+#if !HWUI_NEW_OPS
mOutGlop->bounds = destination;
+#endif
return *this;
}
@@ -516,7 +518,9 @@
mOutGlop->transform.modelView.loadTranslate(left, top, 0.0f);
mOutGlop->transform.modelView.scale(destination.getWidth(), destination.getHeight(), 1.0f);
+#if !HWUI_NEW_OPS
mOutGlop->bounds = destination;
+#endif
return *this;
}
@@ -524,8 +528,10 @@
TRIGGER_STAGE(kModelViewStage);
mOutGlop->transform.modelView.loadTranslate(offsetX, offsetY, 0.0f);
+#if !HWUI_NEW_OPS
mOutGlop->bounds = source;
mOutGlop->bounds.translate(offsetX, offsetY);
+#endif
return *this;
}
@@ -545,8 +551,10 @@
}
mOutGlop->transform.modelView.loadTranslate(offsetX, offsetY, 0.0f);
+#if !HWUI_NEW_OPS
mOutGlop->bounds = source;
mOutGlop->bounds.translate(offsetX, offsetY);
+#endif
return *this;
}
@@ -643,7 +651,9 @@
// Final step: populate program and map bounds into render target space
mOutGlop->fill.program = mCaches.programCache.get(mDescription);
+#if !HWUI_NEW_OPS
mOutGlop->transform.meshTransform().mapRect(mOutGlop->bounds);
+#endif
}
void GlopBuilder::dump(const Glop& glop) {
@@ -683,7 +693,9 @@
ALOGD_IF(glop.roundRectClipState, "Glop RRCS %p", glop.roundRectClipState);
ALOGD("Glop blend %d %d", glop.blend.src, glop.blend.dst);
+#if !HWUI_NEW_OPS
ALOGD("Glop bounds " RECT_STRING, RECT_ARGS(glop.bounds));
+#endif
}
} /* namespace uirenderer */
diff --git a/libs/hwui/JankTracker.cpp b/libs/hwui/JankTracker.cpp
index 2246cf9c..d1ff670 100644
--- a/libs/hwui/JankTracker.cpp
+++ b/libs/hwui/JankTracker.cpp
@@ -15,6 +15,8 @@
*/
#include "JankTracker.h"
+#include "Properties.h"
+
#include <algorithm>
#include <cutils/ashmem.h>
#include <cutils/log.h>
@@ -54,32 +56,35 @@
static const int64_t IGNORE_EXCEEDING = seconds_to_nanoseconds(10);
/*
- * Frames that are exempt from jank metrics.
- * First-draw frames, for example, are expected to
- * be slow, this is hidden from the user with window animations and
- * other tricks
- *
- * Similarly, we don't track direct-drawing via Surface:lockHardwareCanvas()
+ * We don't track direct-drawing via Surface:lockHardwareCanvas()
* for now
*
* TODO: kSurfaceCanvas can negatively impact other drawing by using up
* time on the RenderThread, figure out how to attribute that as a jank-causer
*/
-static const int64_t EXEMPT_FRAMES_FLAGS
- = FrameInfoFlags::WindowLayoutChanged
- | FrameInfoFlags::SurfaceCanvas;
+static const int64_t EXEMPT_FRAMES_FLAGS = FrameInfoFlags::SurfaceCanvas;
// The bucketing algorithm controls so to speak
// If a frame is <= to this it goes in bucket 0
-static const uint32_t kBucketMinThreshold = 7;
+static const uint32_t kBucketMinThreshold = 5;
// If a frame is > this, start counting in increments of 2ms
static const uint32_t kBucket2msIntervals = 32;
// If a frame is > this, start counting in increments of 4ms
static const uint32_t kBucket4msIntervals = 48;
+// For testing purposes to try and eliminate test infra overhead we will
+// consider any unknown delay of frame start as part of the test infrastructure
+// and filter it out of the frame profile data
+static FrameInfoIndex sFrameStart = FrameInfoIndex::IntendedVsync;
+
+// The interval of the slow frame histogram
+static const uint32_t kSlowFrameBucketIntervalMs = 50;
+// The start point of the slow frame bucket in ms
+static const uint32_t kSlowFrameBucketStartMs = 150;
+
// This will be called every frame, performance sensitive
// Uses bit twiddling to avoid branching while achieving the packing desired
-static uint32_t frameCountIndexForFrameTime(nsecs_t frameTime, uint32_t max) {
+static uint32_t frameCountIndexForFrameTime(nsecs_t frameTime) {
uint32_t index = static_cast<uint32_t>(ns2ms(frameTime));
// If index > kBucketMinThreshold mask will be 0xFFFFFFFF as a result
// of negating 1 (twos compliment, yaay) else mask will be 0
@@ -97,7 +102,7 @@
// be a pretty garbage value right now. However, mask is 0 so we'll end
// up with the desired result of 0.
index = (index - kBucketMinThreshold) & mask;
- return index < max ? index : max;
+ return index;
}
// Only called when dumping stats, less performance sensitive
@@ -204,63 +209,34 @@
}
-static bool shouldReplace(SlowFrame& existing, SlowFrame& candidate) {
- if (candidate.whenHours - existing.whenHours >= 24) {
- // If the old slowframe is over 24 hours older than the candidate,
- // replace it. It's too stale
- return true;
- }
- if (candidate.frametimeMs > existing.frametimeMs) {
- return true;
- }
- return false;
-}
-
-void JankTracker::updateSlowest(const FrameInfo& frame) {
- uint16_t durationMs = static_cast<uint16_t>(std::min(
- ns2ms(frame[FrameInfoIndex::FrameCompleted] - frame[FrameInfoIndex::IntendedVsync]),
- static_cast<nsecs_t>(std::numeric_limits<uint16_t>::max())));
- uint16_t startHours = static_cast<uint16_t>(std::lround(
- ns2s(frame[FrameInfoIndex::IntendedVsync]) / 3600.0f));
- SlowFrame* toReplace = nullptr;
- SlowFrame thisFrame{startHours, durationMs};
- // First find the best candidate for replacement
- for (SlowFrame& existing : mData->slowestFrames) {
- // If we should replace the current data with the replacement candidate,
- // it means the current data is worse than the replacement candidate
- if (!toReplace || shouldReplace(existing, *toReplace)) {
- toReplace = &existing;
- }
- }
- // Now see if we should replace it
- if (shouldReplace(*toReplace, thisFrame)) {
- *toReplace = thisFrame;
- }
-}
-
void JankTracker::addFrame(const FrameInfo& frame) {
mData->totalFrameCount++;
// Fast-path for jank-free frames
int64_t totalDuration =
- frame[FrameInfoIndex::FrameCompleted] - frame[FrameInfoIndex::IntendedVsync];
- uint32_t framebucket = frameCountIndexForFrameTime(
- totalDuration, mData->frameCounts.size());
+ frame[FrameInfoIndex::FrameCompleted] - frame[sFrameStart];
+ uint32_t framebucket = frameCountIndexForFrameTime(totalDuration);
// Keep the fast path as fast as possible.
if (CC_LIKELY(totalDuration < mFrameInterval)) {
mData->frameCounts[framebucket]++;
return;
}
- // For slowest frames we are still interested in frames that are otherwise
- // exempt (such as first-draw). Although those frames don't directly impact
- // smoothness, they do impact responsiveness.
- updateSlowest(frame);
-
+ // Only things like Surface.lockHardwareCanvas() are exempt from tracking
if (frame[FrameInfoIndex::Flags] & EXEMPT_FRAMES_FLAGS) {
return;
}
- mData->frameCounts[framebucket]++;
+ if (framebucket <= mData->frameCounts.size()) {
+ mData->frameCounts[framebucket]++;
+ } else {
+ framebucket = (ns2ms(totalDuration) - kSlowFrameBucketStartMs)
+ / kSlowFrameBucketIntervalMs;
+ framebucket = std::min(framebucket,
+ static_cast<uint32_t>(mData->slowFrameCounts.size() - 1));
+ framebucket = std::max(framebucket, 0u);
+ mData->slowFrameCounts[framebucket]++;
+ }
+
mData->jankFrameCount++;
for (int i = 0; i < NUM_BUCKETS; i++) {
@@ -280,6 +256,9 @@
}
void JankTracker::dumpData(const ProfileData* data, int fd) {
+ if (sFrameStart != FrameInfoIndex::IntendedVsync) {
+ dprintf(fd, "\nNote: Data has been filtered!");
+ }
dprintf(fd, "\nStats since: %" PRIu64 "ns", data->statStartTime);
dprintf(fd, "\nTotal frames rendered: %u", data->totalFrameCount);
dprintf(fd, "\nJanky frames: %u (%.2f%%)", data->jankFrameCount,
@@ -288,14 +267,18 @@
dprintf(fd, "\n90th percentile: %ums", findPercentile(data, 90));
dprintf(fd, "\n95th percentile: %ums", findPercentile(data, 95));
dprintf(fd, "\n99th percentile: %ums", findPercentile(data, 99));
- dprintf(fd, "\nSlowest frames over last 24h: ");
- for (auto& slowFrame : data->slowestFrames) {
- if (!slowFrame.frametimeMs) continue;
- dprintf(fd, "%ums ", slowFrame.frametimeMs);
- }
for (int i = 0; i < NUM_BUCKETS; i++) {
dprintf(fd, "\nNumber %s: %u", JANK_TYPE_NAMES[i], data->jankTypeCounts[i]);
}
+ dprintf(fd, "\nHISTOGRAM:");
+ for (size_t i = 0; i < data->frameCounts.size(); i++) {
+ dprintf(fd, " %ums=%u", frameTimeForFrameCountIndex(i),
+ data->frameCounts[i]);
+ }
+ for (size_t i = 0; i < data->slowFrameCounts.size(); i++) {
+ dprintf(fd, " %zums=%u", (i * kSlowFrameBucketIntervalMs) + kSlowFrameBucketStartMs,
+ data->slowFrameCounts[i]);
+ }
dprintf(fd, "\n");
}
@@ -305,11 +288,20 @@
mData->totalFrameCount = 0;
mData->jankFrameCount = 0;
mData->statStartTime = systemTime(CLOCK_MONOTONIC);
+ sFrameStart = Properties::filterOutTestOverhead
+ ? FrameInfoIndex::HandleInputStart
+ : FrameInfoIndex::IntendedVsync;
}
uint32_t JankTracker::findPercentile(const ProfileData* data, int percentile) {
int pos = percentile * data->totalFrameCount / 100;
int remaining = data->totalFrameCount - pos;
+ for (int i = data->slowFrameCounts.size() - 1; i >= 0; i--) {
+ remaining -= data->slowFrameCounts[i];
+ if (remaining <= 0) {
+ return (i * kSlowFrameBucketIntervalMs) + kSlowFrameBucketStartMs;
+ }
+ }
for (int i = data->frameCounts.size() - 1; i >= 0; i--) {
remaining -= data->frameCounts[i];
if (remaining <= 0) {
diff --git a/libs/hwui/JankTracker.h b/libs/hwui/JankTracker.h
index 1a4a489..84b8c3f 100644
--- a/libs/hwui/JankTracker.h
+++ b/libs/hwui/JankTracker.h
@@ -39,23 +39,18 @@
NUM_BUCKETS,
};
-struct SlowFrame {
- uint16_t whenHours; // When this occurred in CLOCK_MONOTONIC in hours
- uint16_t frametimeMs; // How long the frame took in ms
-};
-
// Try to keep as small as possible, should match ASHMEM_SIZE in
// GraphicsStatsService.java
struct ProfileData {
std::array<uint32_t, NUM_BUCKETS> jankTypeCounts;
// See comments on kBucket* constants for what this holds
- std::array<uint32_t, 55> frameCounts;
+ std::array<uint32_t, 57> frameCounts;
+ // Holds a histogram of frame times in 50ms increments from 150ms to 5s
+ std::array<uint16_t, 97> slowFrameCounts;
uint32_t totalFrameCount;
uint32_t jankFrameCount;
nsecs_t statStartTime;
-
- std::array<SlowFrame, 10> slowestFrames;
};
// TODO: Replace DrawProfiler with this
@@ -78,7 +73,6 @@
private:
void freeData();
void setFrameInterval(nsecs_t frameIntervalNanos);
- void updateSlowest(const FrameInfo& frame);
static uint32_t findPercentile(const ProfileData* data, int p);
static void dumpData(const ProfileData* data, int fd);
diff --git a/libs/hwui/LayerBuilder.cpp b/libs/hwui/LayerBuilder.cpp
index e6a95ff..eea11bf 100644
--- a/libs/hwui/LayerBuilder.cpp
+++ b/libs/hwui/LayerBuilder.cpp
@@ -236,6 +236,21 @@
mClearRects.push_back(rect);
}
+void LayerBuilder::onDeferOp(LinearAllocator& allocator, const BakedOpState* bakedState) {
+ if (bakedState->op->opId != RecordedOpId::CopyToLayerOp) {
+ // First non-CopyToLayer, so stop stashing up layer clears for unclipped save layers,
+ // and issue them together in one draw.
+ flushLayerClears(allocator);
+
+ if (CC_UNLIKELY(activeUnclippedSaveLayers.empty()
+ && bakedState->computedState.opaqueOverClippedBounds
+ && bakedState->computedState.clippedBounds.contains(repaintRect))) {
+ // discard all deferred drawing ops, since new one will occlude them
+ clear();
+ }
+ }
+}
+
void LayerBuilder::flushLayerClears(LinearAllocator& allocator) {
if (CC_UNLIKELY(!mClearRects.empty())) {
const int vertCount = mClearRects.size() * 4;
@@ -270,11 +285,7 @@
void LayerBuilder::deferUnmergeableOp(LinearAllocator& allocator,
BakedOpState* op, batchid_t batchId) {
- if (batchId != OpBatchType::CopyToLayer) {
- // if first op after one or more unclipped saveLayers, flush the layer clears
- flushLayerClears(allocator);
- }
-
+ onDeferOp(allocator, op);
OpBatch* targetBatch = mBatchLookup[batchId];
size_t insertBatchIndex = mBatches.size();
@@ -295,10 +306,7 @@
void LayerBuilder::deferMergeableOp(LinearAllocator& allocator,
BakedOpState* op, batchid_t batchId, mergeid_t mergeId) {
- if (batchId != OpBatchType::CopyToLayer) {
- // if first op after one or more unclipped saveLayers, flush the layer clears
- flushLayerClears(allocator);
- }
+ onDeferOp(allocator, op);
MergingOpBatch* targetBatch = nullptr;
// Try to merge with any existing batch with same mergeId
@@ -348,6 +356,14 @@
}
}
+void LayerBuilder::clear() {
+ mBatches.clear();
+ for (int i = 0; i < OpBatchType::Count; i++) {
+ mBatchLookup[i] = nullptr;
+ mMergingBatchLookup[i].clear();
+ }
+}
+
void LayerBuilder::dump() const {
ALOGD("LayerBuilder %p, %ux%u buffer %p, blo %p, rn %p (%s)",
this, width, height, offscreenBuffer, beginLayerOp,
diff --git a/libs/hwui/LayerBuilder.h b/libs/hwui/LayerBuilder.h
index 4a7ca2d..4de432c 100644
--- a/libs/hwui/LayerBuilder.h
+++ b/libs/hwui/LayerBuilder.h
@@ -100,9 +100,7 @@
return mBatches.empty();
}
- void clear() {
- mBatches.clear();
- }
+ void clear();
void dump() const;
@@ -117,6 +115,7 @@
// list of deferred CopyFromLayer ops, to be deferred upon encountering EndUnclippedLayerOps
std::vector<BakedOpState*> activeUnclippedSaveLayers;
private:
+ void onDeferOp(LinearAllocator& allocator, const BakedOpState* bakedState);
void flushLayerClears(LinearAllocator& allocator);
std::vector<BatchBase*> mBatches;
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index c099427..53ea7fa 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -1413,7 +1413,9 @@
if (type == GlopRenderType::Standard && !mRenderState.stencil().isWriteEnabled()) {
// TODO: specify more clearly when a draw should dirty the layer.
// is writing to the stencil the only time we should ignore this?
+#if !HWUI_NEW_OPS
dirtyLayer(glop.bounds.left, glop.bounds.top, glop.bounds.right, glop.bounds.bottom);
+#endif
mDirty = true;
}
}
diff --git a/libs/hwui/Properties.cpp b/libs/hwui/Properties.cpp
index bbd8c72..6f68c2b 100644
--- a/libs/hwui/Properties.cpp
+++ b/libs/hwui/Properties.cpp
@@ -66,6 +66,8 @@
bool Properties::waitForGpuCompletion = false;
+bool Properties::filterOutTestOverhead = false;
+
static int property_get_int(const char* key, int defaultValue) {
char buf[PROPERTY_VALUE_MAX] = {'\0',};
@@ -156,6 +158,8 @@
textureCacheFlushRate = std::max(0.0f, std::min(1.0f,
property_get_float(PROPERTY_TEXTURE_CACHE_FLUSH_RATE, DEFAULT_TEXTURE_CACHE_FLUSH_RATE)));
+ filterOutTestOverhead = property_get_bool(PROPERTY_FILTER_TEST_OVERHEAD, false);
+
return (prevDebugLayersUpdates != debugLayersUpdates)
|| (prevDebugOverdraw != debugOverdraw)
|| (prevDebugStencilClip != debugStencilClip);
diff --git a/libs/hwui/Properties.h b/libs/hwui/Properties.h
index 249b5b0..171873d 100644
--- a/libs/hwui/Properties.h
+++ b/libs/hwui/Properties.h
@@ -151,6 +151,8 @@
*/
#define PROPERTY_ENABLE_PARTIAL_UPDATES "debug.hwui.enable_partial_updates"
+#define PROPERTY_FILTER_TEST_OVERHEAD "debug.hwui.filter_test_overhead"
+
///////////////////////////////////////////////////////////////////////////////
// Runtime configuration properties
///////////////////////////////////////////////////////////////////////////////
@@ -294,6 +296,10 @@
// Should be used only by test apps
static bool waitForGpuCompletion;
+ // Should only be set by automated tests to try and filter out
+ // any overhead they add
+ static bool filterOutTestOverhead;
+
private:
static ProfileType sProfileType;
static bool sDisableProfileBars;
diff --git a/libs/hwui/PropertyValuesHolder.cpp b/libs/hwui/PropertyValuesHolder.cpp
index 8f837f6..0932d65 100644
--- a/libs/hwui/PropertyValuesHolder.cpp
+++ b/libs/hwui/PropertyValuesHolder.cpp
@@ -53,7 +53,7 @@
} else {
animatedValue = mStartValue * (1 - fraction) + mEndValue * fraction;
}
- mGroup->setPropertyValue(mPropertyId, animatedValue);
+ mGroup->mutateProperties()->setPropertyValue(mPropertyId, animatedValue);
}
inline U8CPU lerp(U8CPU fromValue, U8CPU toValue, float fraction) {
@@ -72,7 +72,7 @@
void FullPathColorPropertyValuesHolder::setFraction(float fraction) {
SkColor animatedValue = interpolateColors(mStartValue, mEndValue, fraction);
- mFullPath->setColorPropertyValue(mPropertyId, animatedValue);
+ mFullPath->mutateProperties()->setColorPropertyValue(mPropertyId, animatedValue);
}
void FullPathPropertyValuesHolder::setFraction(float fraction) {
@@ -82,17 +82,17 @@
} else {
animatedValue = mStartValue * (1 - fraction) + mEndValue * fraction;
}
- mFullPath->setPropertyValue(mPropertyId, animatedValue);
+ mFullPath->mutateProperties()->setPropertyValue(mPropertyId, animatedValue);
}
void PathDataPropertyValuesHolder::setFraction(float fraction) {
VectorDrawableUtils::interpolatePaths(&mPathData, mStartValue, mEndValue, fraction);
- mPath->setPathData(mPathData);
+ mPath->mutateProperties()->setData(mPathData);
}
void RootAlphaPropertyValuesHolder::setFraction(float fraction) {
float animatedValue = mStartValue * (1 - fraction) + mEndValue * fraction;
- mTree->setRootAlpha(animatedValue);
+ mTree->mutateProperties()->setRootAlpha(animatedValue);
}
} // namepace uirenderer
diff --git a/libs/hwui/RecordedOp.h b/libs/hwui/RecordedOp.h
index 64c604a..0271a80 100644
--- a/libs/hwui/RecordedOp.h
+++ b/libs/hwui/RecordedOp.h
@@ -419,6 +419,14 @@
TextureLayerOp(BASE_PARAMS_PAINTLESS, Layer* layer)
: SUPER_PAINTLESS(TextureLayerOp)
, layer(layer) {}
+
+ // Copy an existing TextureLayerOp, replacing the underlying matrix
+ TextureLayerOp(const TextureLayerOp& op, const Matrix4& replacementMatrix)
+ : RecordedOp(RecordedOpId::TextureLayerOp, op.unmappedBounds, replacementMatrix,
+ op.localClip, op.paint)
+ , layer(op.layer) {
+
+ }
Layer* layer;
};
diff --git a/libs/hwui/RecordingCanvas.cpp b/libs/hwui/RecordingCanvas.cpp
index f43dade..b78497d 100644
--- a/libs/hwui/RecordingCanvas.cpp
+++ b/libs/hwui/RecordingCanvas.cpp
@@ -430,10 +430,11 @@
}
void RecordingCanvas::drawVectorDrawable(VectorDrawableRoot* tree) {
+ mDisplayList->pushStagingFunctors.push_back(tree->getFunctor());
mDisplayList->ref(tree);
addOp(alloc().create_trivial<VectorDrawableOp>(
tree,
- Rect(tree->getBounds()),
+ Rect(tree->stagingProperties()->getBounds()),
*(mState.currentSnapshot()->transform),
getRecordedClip()));
}
@@ -576,15 +577,9 @@
// Note that the backing layer has *not* yet been updated, so don't trust
// its width, height, transform, etc...!
- Matrix4 totalTransform(*(mState.currentSnapshot()->transform));
- if (layerHandle->getTransform()) {
- Matrix4 layerTransform(*layerHandle->getTransform());
- totalTransform.multiply(layerTransform);
- }
-
addOp(alloc().create_trivial<TextureLayerOp>(
Rect(layerHandle->getWidth(), layerHandle->getHeight()),
- totalTransform,
+ *(mState.currentSnapshot()->transform),
getRecordedClip(),
layerHandle->backingLayer()));
}
diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp
index 61441ce..9578486 100644
--- a/libs/hwui/RenderNode.cpp
+++ b/libs/hwui/RenderNode.cpp
@@ -68,7 +68,7 @@
}
RenderNode::~RenderNode() {
- deleteDisplayList();
+ deleteDisplayList(nullptr);
delete mStagingDisplayList;
#if HWUI_NEW_OPS
LOG_ALWAYS_FATAL_IF(mLayer, "layer missed detachment!");
@@ -88,7 +88,7 @@
// If mParentCount == 0 we are the sole reference to this RenderNode,
// so immediately free the old display list
if (!mParentCount && !mStagingDisplayList) {
- deleteDisplayList();
+ deleteDisplayList(nullptr);
}
}
@@ -462,7 +462,7 @@
}
#endif
-void RenderNode::syncDisplayList() {
+void RenderNode::syncDisplayList(TreeObserver* observer) {
// Make sure we inc first so that we don't fluctuate between 0 and 1,
// which would thrash the layer cache
if (mStagingDisplayList) {
@@ -470,13 +470,16 @@
child->renderNode->incParentRefCount();
}
}
- deleteDisplayList();
+ deleteDisplayList(observer);
mDisplayList = mStagingDisplayList;
mStagingDisplayList = nullptr;
if (mDisplayList) {
for (size_t i = 0; i < mDisplayList->getFunctors().size(); i++) {
(*mDisplayList->getFunctors()[i])(DrawGlInfo::kModeSync, nullptr);
}
+ for (size_t i = 0; i < mDisplayList->getPushStagingFunctors().size(); i++) {
+ (*mDisplayList->getPushStagingFunctors()[i])();
+ }
}
}
@@ -486,15 +489,15 @@
// Damage with the old display list first then the new one to catch any
// changes in isRenderable or, in the future, bounds
damageSelf(info);
- syncDisplayList();
+ syncDisplayList(info.observer);
damageSelf(info);
}
}
-void RenderNode::deleteDisplayList() {
+void RenderNode::deleteDisplayList(TreeObserver* observer) {
if (mDisplayList) {
for (auto&& child : mDisplayList->getChildren()) {
- child->renderNode->decParentRefCount();
+ child->renderNode->decParentRefCount(observer);
}
}
delete mDisplayList;
@@ -526,32 +529,35 @@
}
}
-void RenderNode::destroyHardwareResources() {
+void RenderNode::destroyHardwareResources(TreeObserver* observer) {
if (mLayer) {
destroyLayer(mLayer);
mLayer = nullptr;
}
if (mDisplayList) {
for (auto&& child : mDisplayList->getChildren()) {
- child->renderNode->destroyHardwareResources();
+ child->renderNode->destroyHardwareResources(observer);
}
if (mNeedsDisplayListSync) {
// Next prepare tree we are going to push a new display list, so we can
// drop our current one now
- deleteDisplayList();
+ deleteDisplayList(observer);
}
}
}
-void RenderNode::decParentRefCount() {
+void RenderNode::decParentRefCount(TreeObserver* observer) {
LOG_ALWAYS_FATAL_IF(!mParentCount, "already 0!");
mParentCount--;
if (!mParentCount) {
+ if (observer) {
+ observer->onMaybeRemovedFromTree(this);
+ }
// If a child of ours is being attached to our parent then this will incorrectly
// destroy its hardware resources. However, this situation is highly unlikely
// and the failure is "just" that the layer is re-created, so this should
// be safe enough
- destroyHardwareResources();
+ destroyHardwareResources(observer);
}
}
diff --git a/libs/hwui/RenderNode.h b/libs/hwui/RenderNode.h
index 8381925..b0136cf 100644
--- a/libs/hwui/RenderNode.h
+++ b/libs/hwui/RenderNode.h
@@ -68,6 +68,7 @@
class SaveOp;
class RestoreToCountOp;
class TreeInfo;
+class TreeObserver;
namespace proto {
class RenderNode;
@@ -154,6 +155,14 @@
}
}
+ VirtualLightRefBase* getUserContext() const {
+ return mUserContext.get();
+ }
+
+ void setUserContext(VirtualLightRefBase* context) {
+ mUserContext = context;
+ }
+
bool isPropertyFieldDirty(DirtyPropertyMask field) const {
return mDirtyPropertyFields & field;
}
@@ -187,7 +196,7 @@
}
ANDROID_API virtual void prepareTree(TreeInfo& info);
- void destroyHardwareResources();
+ void destroyHardwareResources(TreeObserver* observer);
// UI thread only!
ANDROID_API void addAnimator(const sp<BaseRenderNodeAnimator>& animator);
@@ -232,6 +241,12 @@
mPositionListener.reset(listener);
}
+ // This is only modified in MODE_FULL, so it can be safely accessed
+ // on the UI thread.
+ ANDROID_API bool hasParents() {
+ return mParentCount;
+ }
+
private:
typedef key_value_pair_t<float, DrawRenderNodeOp*> ZDrawRenderNodeOpPair;
@@ -291,7 +306,7 @@
void syncProperties();
- void syncDisplayList();
+ void syncDisplayList(TreeObserver* observer);
void prepareTreeImpl(TreeInfo& info, bool functorsNeedLayer);
void pushStagingPropertiesChanges(TreeInfo& info);
@@ -302,13 +317,14 @@
#endif
void prepareLayer(TreeInfo& info, uint32_t dirtyMask);
void pushLayerUpdate(TreeInfo& info);
- void deleteDisplayList();
+ void deleteDisplayList(TreeObserver* observer);
void damageSelf(TreeInfo& info);
void incParentRefCount() { mParentCount++; }
- void decParentRefCount();
+ void decParentRefCount(TreeObserver* observer);
String8 mName;
+ sp<VirtualLightRefBase> mUserContext;
uint32_t mDirtyPropertyFields;
RenderProperties mProperties;
diff --git a/libs/hwui/RenderProperties.cpp b/libs/hwui/RenderProperties.cpp
index f577785..5ebf545 100644
--- a/libs/hwui/RenderProperties.cpp
+++ b/libs/hwui/RenderProperties.cpp
@@ -155,6 +155,23 @@
ALOGD("%*s(ClipRect %d, %d, %d, %d)", level * 2, "",
(int)clipRect.left, (int)clipRect.top, (int)clipRect.right, (int)clipRect.bottom);
}
+
+ if (getRevealClip().willClip()) {
+ Rect bounds;
+ getRevealClip().getBounds(&bounds);
+ ALOGD("%*s(Clip to reveal clip with bounds %.2f %.2f %.2f %.2f)", level * 2, "",
+ RECT_ARGS(bounds));
+ }
+
+ auto& outline = mPrimitiveFields.mOutline;
+ if (outline.getShouldClip()) {
+ if (outline.isEmpty()) {
+ ALOGD("%*s(Clip to empty outline)", level * 2, "");
+ } else if (outline.willClip()) {
+ ALOGD("%*s(Clip to outline with bounds %.2f %.2f %.2f %.2f)", level * 2, "",
+ RECT_ARGS(outline.getBounds()));
+ }
+ }
}
void RenderProperties::updateMatrix() {
diff --git a/libs/hwui/SkiaCanvas.cpp b/libs/hwui/SkiaCanvas.cpp
index 5d24fa0..1b459c1 100644
--- a/libs/hwui/SkiaCanvas.cpp
+++ b/libs/hwui/SkiaCanvas.cpp
@@ -747,11 +747,7 @@
}
void SkiaCanvas::drawVectorDrawable(VectorDrawableRoot* vectorDrawable) {
- const SkBitmap& bitmap = vectorDrawable->getBitmapUpdateIfDirty();
- SkRect bounds = vectorDrawable->getBounds();
- drawBitmap(bitmap, 0, 0, bitmap.width(), bitmap.height(),
- bounds.fLeft, bounds.fTop, bounds.fRight, bounds.fBottom,
- vectorDrawable->getPaint());
+ vectorDrawable->drawStaging(this);
}
// ----------------------------------------------------------------------------
diff --git a/libs/hwui/SkiaCanvasProxy.cpp b/libs/hwui/SkiaCanvasProxy.cpp
index c612480..9df32b28 100644
--- a/libs/hwui/SkiaCanvasProxy.cpp
+++ b/libs/hwui/SkiaCanvasProxy.cpp
@@ -318,12 +318,17 @@
posArray = pointStorage.get();
}
- // compute conservative bounds
- // NOTE: We could call the faster paint.getFontBounds for a less accurate,
- // but even more conservative bounds if this is too slow.
+ // Compute conservative bounds. If the content has already been processed
+ // by Minikin then it had already computed these bounds. Unfortunately,
+ // there is no way to capture those bounds as part of the Skia drawPosText
+ // API so we need to do that computation again here.
SkRect bounds;
- glyphs.paint.measureText(glyphs.glyphIDs, glyphs.count << 1, &bounds);
- bounds.offset(x, y);
+ for (int i = 0; i < glyphs.count; i++) {
+ SkRect glyphBounds;
+ glyphs.paint.measureText(&glyphs.glyphIDs[i], sizeof(uint16_t), &glyphBounds);
+ glyphBounds.offset(pos[i].fX, pos[i].fY);
+ bounds.join(glyphBounds);
+ }
static_assert(sizeof(SkPoint) == sizeof(float)*2, "SkPoint is no longer two floats");
mCanvas->drawGlyphs(glyphs.glyphIDs, &posArray[0].fX, glyphs.count, glyphs.paint, x, y,
diff --git a/libs/hwui/TreeInfo.h b/libs/hwui/TreeInfo.h
index accd303..a43e544 100644
--- a/libs/hwui/TreeInfo.h
+++ b/libs/hwui/TreeInfo.h
@@ -32,6 +32,7 @@
class DamageAccumulator;
class LayerUpdateQueue;
class OpenGLRenderer;
+class RenderNode;
class RenderState;
class ErrorHandler {
@@ -41,6 +42,17 @@
~ErrorHandler() {}
};
+class TreeObserver {
+public:
+ // Called when a RenderNode's parent count hits 0.
+ // Due to the unordered nature of tree pushes, once prepareTree
+ // is finished it is possible that the node was "resurrected" and has
+ // a non-zero parent count.
+ virtual void onMaybeRemovedFromTree(RenderNode* node) {}
+protected:
+ ~TreeObserver() {}
+};
+
// This would be a struct, but we want to PREVENT_COPY_AND_ASSIGN
class TreeInfo {
PREVENT_COPY_AND_ASSIGN(TreeInfo);
@@ -86,6 +98,10 @@
#endif
ErrorHandler* errorHandler = nullptr;
+ // Optional, may be nullptr. Used to allow things to observe interesting
+ // tree state changes
+ TreeObserver* observer = nullptr;
+
// Frame number for use with synchronized surfaceview position updating
int64_t frameNumber = -1;
int32_t windowInsetLeft = 0;
diff --git a/libs/hwui/VectorDrawable.cpp b/libs/hwui/VectorDrawable.cpp
index d35f764..adfe45c 100644
--- a/libs/hwui/VectorDrawable.cpp
+++ b/libs/hwui/VectorDrawable.cpp
@@ -17,6 +17,7 @@
#include "VectorDrawable.h"
#include "PathParser.h"
+#include "SkColorFilter.h"
#include "SkImageInfo.h"
#include "SkShader.h"
#include <utils/Log.h>
@@ -32,41 +33,36 @@
const int Tree::MAX_CACHED_BITMAP_SIZE = 2048;
-void Path::draw(SkCanvas* outCanvas, const SkMatrix& groupStackedMatrix, float scaleX, float scaleY) {
+void Path::draw(SkCanvas* outCanvas, const SkMatrix& groupStackedMatrix, float scaleX, float scaleY,
+ bool useStagingData) {
float matrixScale = getMatrixScale(groupStackedMatrix);
if (matrixScale == 0) {
// When either x or y is scaled to 0, we don't need to draw anything.
return;
}
- const SkPath updatedPath = getUpdatedPath();
SkMatrix pathMatrix(groupStackedMatrix);
pathMatrix.postScale(scaleX, scaleY);
//TODO: try apply the path matrix to the canvas instead of creating a new path.
SkPath renderPath;
renderPath.reset();
- renderPath.addPath(updatedPath, pathMatrix);
+
+ if (useStagingData) {
+ SkPath tmpPath;
+ getStagingPath(&tmpPath);
+ renderPath.addPath(tmpPath, pathMatrix);
+ } else {
+ renderPath.addPath(getUpdatedPath(), pathMatrix);
+ }
float minScale = fmin(scaleX, scaleY);
float strokeScale = minScale * matrixScale;
- drawPath(outCanvas, renderPath, strokeScale, pathMatrix);
-}
-
-void Path::setPathData(const Data& data) {
- if (mData == data) {
- return;
- }
- // Updates the path data. Note that we don't generate a new Skia path right away
- // because there are cases where the animation is changing the path data, but the view
- // that hosts the VD has gone off screen, in which case we won't even draw. So we
- // postpone the Skia path generation to the draw time.
- mData = data;
- mSkPathDirty = true;
+ drawPath(outCanvas, renderPath, strokeScale, pathMatrix, useStagingData);
}
void Path::dump() {
- ALOGD("Path: %s has %zu points", mName.c_str(), mData.points.size());
+ ALOGD("Path: %s has %zu points", mName.c_str(), mProperties.getData().points.size());
}
float Path::getMatrixScale(const SkMatrix& groupStackedMatrix) {
@@ -95,213 +91,215 @@
}
return matrixScale;
}
+
+// Called from UI thread during the initial setup/theme change.
Path::Path(const char* pathStr, size_t strLength) {
PathParser::ParseResult result;
- PathParser::getPathDataFromString(&mData, &result, pathStr, strLength);
- if (!result.failureOccurred) {
- VectorDrawableUtils::verbsToPath(&mSkPath, mData);
- }
-}
-
-Path::Path(const Data& data) {
- mData = data;
- // Now we need to construct a path
- VectorDrawableUtils::verbsToPath(&mSkPath, data);
+ Data data;
+ PathParser::getPathDataFromString(&data, &result, pathStr, strLength);
+ mStagingProperties.setData(data);
}
Path::Path(const Path& path) : Node(path) {
- mData = path.mData;
- VectorDrawableUtils::verbsToPath(&mSkPath, mData);
-}
-
-bool Path::canMorph(const Data& morphTo) {
- return VectorDrawableUtils::canMorph(mData, morphTo);
-}
-
-bool Path::canMorph(const Path& path) {
- return canMorph(path.mData);
+ mStagingProperties.syncProperties(path.mStagingProperties);
}
const SkPath& Path::getUpdatedPath() {
if (mSkPathDirty) {
mSkPath.reset();
- VectorDrawableUtils::verbsToPath(&mSkPath, mData);
+ VectorDrawableUtils::verbsToPath(&mSkPath, mProperties.getData());
mSkPathDirty = false;
}
return mSkPath;
}
-void Path::setPath(const char* pathStr, size_t strLength) {
- PathParser::ParseResult result;
- mSkPathDirty = true;
- PathParser::getPathDataFromString(&mData, &result, pathStr, strLength);
+void Path::getStagingPath(SkPath* outPath) {
+ outPath->reset();
+ VectorDrawableUtils::verbsToPath(outPath, mStagingProperties.getData());
+}
+
+void Path::syncProperties() {
+ if (mStagingPropertiesDirty) {
+ mProperties.syncProperties(mStagingProperties);
+ } else {
+ mStagingProperties.syncProperties(mProperties);
+ }
+ mStagingPropertiesDirty = false;
}
FullPath::FullPath(const FullPath& path) : Path(path) {
- mProperties = path.mProperties;
- SkRefCnt_SafeAssign(mStrokeGradient, path.mStrokeGradient);
- SkRefCnt_SafeAssign(mFillGradient, path.mFillGradient);
+ mStagingProperties.syncProperties(path.mStagingProperties);
+}
+
+static void applyTrim(SkPath* outPath, const SkPath& inPath, float trimPathStart, float trimPathEnd,
+ float trimPathOffset) {
+ if (trimPathStart == 0.0f && trimPathEnd == 1.0f) {
+ *outPath = inPath;
+ return;
+ }
+ outPath->reset();
+ if (trimPathStart == trimPathEnd) {
+ // Trimmed path should be empty.
+ return;
+ }
+ SkPathMeasure measure(inPath, false);
+ float len = SkScalarToFloat(measure.getLength());
+ float start = len * fmod((trimPathStart + trimPathOffset), 1.0f);
+ float end = len * fmod((trimPathEnd + trimPathOffset), 1.0f);
+
+ if (start > end) {
+ measure.getSegment(start, len, outPath, true);
+ if (end > 0) {
+ measure.getSegment(0, end, outPath, true);
+ }
+ } else {
+ measure.getSegment(start, end, outPath, true);
+ }
}
const SkPath& FullPath::getUpdatedPath() {
- if (!mSkPathDirty && !mTrimDirty) {
+ if (!mSkPathDirty && !mProperties.mTrimDirty) {
return mTrimmedSkPath;
}
Path::getUpdatedPath();
- if (mProperties.trimPathStart != 0.0f || mProperties.trimPathEnd != 1.0f) {
- applyTrim();
+ if (mProperties.getTrimPathStart() != 0.0f || mProperties.getTrimPathEnd() != 1.0f) {
+ mProperties.mTrimDirty = false;
+ applyTrim(&mTrimmedSkPath, mSkPath, mProperties.getTrimPathStart(),
+ mProperties.getTrimPathEnd(), mProperties.getTrimPathOffset());
return mTrimmedSkPath;
} else {
return mSkPath;
}
}
-void FullPath::updateProperties(float strokeWidth, SkColor strokeColor, float strokeAlpha,
- SkColor fillColor, float fillAlpha, float trimPathStart, float trimPathEnd,
- float trimPathOffset, float strokeMiterLimit, int strokeLineCap, int strokeLineJoin,
- int fillType) {
- mProperties.strokeWidth = strokeWidth;
- mProperties.strokeColor = strokeColor;
- mProperties.strokeAlpha = strokeAlpha;
- mProperties.fillColor = fillColor;
- mProperties.fillAlpha = fillAlpha;
- mProperties.strokeMiterLimit = strokeMiterLimit;
- mProperties.strokeLineCap = strokeLineCap;
- mProperties.strokeLineJoin = strokeLineJoin;
- mProperties.fillType = fillType;
-
- // If any trim property changes, mark trim dirty and update the trim path
- setTrimPathStart(trimPathStart);
- setTrimPathEnd(trimPathEnd);
- setTrimPathOffset(trimPathOffset);
+void FullPath::getStagingPath(SkPath* outPath) {
+ Path::getStagingPath(outPath);
+ SkPath inPath = *outPath;
+ applyTrim(outPath, inPath, mStagingProperties.getTrimPathStart(),
+ mStagingProperties.getTrimPathEnd(), mStagingProperties.getTrimPathOffset());
}
+void FullPath::dump() {
+ Path::dump();
+ ALOGD("stroke width, color, alpha: %f, %d, %f, fill color, alpha: %d, %f",
+ mProperties.getStrokeWidth(), mProperties.getStrokeColor(), mProperties.getStrokeAlpha(),
+ mProperties.getFillColor(), mProperties.getFillAlpha());
+}
+
+
inline SkColor applyAlpha(SkColor color, float alpha) {
int alphaBytes = SkColorGetA(color);
return SkColorSetA(color, alphaBytes * alpha);
}
void FullPath::drawPath(SkCanvas* outCanvas, SkPath& renderPath, float strokeScale,
- const SkMatrix& matrix){
+ const SkMatrix& matrix, bool useStagingData){
+ const FullPathProperties& properties = useStagingData ? mStagingProperties : mProperties;
+
// Draw path's fill, if fill color or gradient is valid
bool needsFill = false;
- if (mFillGradient != nullptr) {
- mPaint.setColor(applyAlpha(SK_ColorBLACK, mProperties.fillAlpha));
- SkShader* newShader = mFillGradient->newWithLocalMatrix(matrix);
- mPaint.setShader(newShader);
+ SkPaint paint;
+ if (properties.getFillGradient() != nullptr) {
+ paint.setColor(applyAlpha(SK_ColorBLACK, properties.getFillAlpha()));
+ SkShader* newShader = properties.getFillGradient()->newWithLocalMatrix(matrix);
+ paint.setShader(newShader);
needsFill = true;
- } else if (mProperties.fillColor != SK_ColorTRANSPARENT) {
- mPaint.setColor(applyAlpha(mProperties.fillColor, mProperties.fillAlpha));
+ } else if (properties.getFillColor() != SK_ColorTRANSPARENT) {
+ paint.setColor(applyAlpha(properties.getFillColor(), properties.getFillAlpha()));
needsFill = true;
}
if (needsFill) {
- mPaint.setStyle(SkPaint::Style::kFill_Style);
- mPaint.setAntiAlias(true);
- SkPath::FillType ft = static_cast<SkPath::FillType>(mProperties.fillType);
+ paint.setStyle(SkPaint::Style::kFill_Style);
+ paint.setAntiAlias(true);
+ SkPath::FillType ft = static_cast<SkPath::FillType>(properties.getFillType());
renderPath.setFillType(ft);
- outCanvas->drawPath(renderPath, mPaint);
+ outCanvas->drawPath(renderPath, paint);
}
- // Draw path's stroke, if stroke color or gradient is valid
+ // Draw path's stroke, if stroke color or Gradient is valid
bool needsStroke = false;
- if (mStrokeGradient != nullptr) {
- mPaint.setColor(applyAlpha(SK_ColorBLACK, mProperties.strokeAlpha));
- SkShader* newShader = mStrokeGradient->newWithLocalMatrix(matrix);
- mPaint.setShader(newShader);
+ if (properties.getStrokeGradient() != nullptr) {
+ paint.setColor(applyAlpha(SK_ColorBLACK, properties.getStrokeAlpha()));
+ SkShader* newShader = properties.getStrokeGradient()->newWithLocalMatrix(matrix);
+ paint.setShader(newShader);
needsStroke = true;
- } else if (mProperties.strokeColor != SK_ColorTRANSPARENT) {
- mPaint.setColor(applyAlpha(mProperties.strokeColor, mProperties.strokeAlpha));
+ } else if (properties.getStrokeColor() != SK_ColorTRANSPARENT) {
+ paint.setColor(applyAlpha(properties.getStrokeColor(), properties.getStrokeAlpha()));
needsStroke = true;
}
if (needsStroke) {
- mPaint.setStyle(SkPaint::Style::kStroke_Style);
- mPaint.setAntiAlias(true);
- mPaint.setStrokeJoin(SkPaint::Join(mProperties.strokeLineJoin));
- mPaint.setStrokeCap(SkPaint::Cap(mProperties.strokeLineCap));
- mPaint.setStrokeMiter(mProperties.strokeMiterLimit);
- mPaint.setStrokeWidth(mProperties.strokeWidth * strokeScale);
- outCanvas->drawPath(renderPath, mPaint);
+ paint.setStyle(SkPaint::Style::kStroke_Style);
+ paint.setAntiAlias(true);
+ paint.setStrokeJoin(SkPaint::Join(properties.getStrokeLineJoin()));
+ paint.setStrokeCap(SkPaint::Cap(properties.getStrokeLineCap()));
+ paint.setStrokeMiter(properties.getStrokeMiterLimit());
+ paint.setStrokeWidth(properties.getStrokeWidth() * strokeScale);
+ outCanvas->drawPath(renderPath, paint);
}
}
-/**
- * Applies trimming to the specified path.
- */
-void FullPath::applyTrim() {
- if (mProperties.trimPathStart == 0.0f && mProperties.trimPathEnd == 1.0f) {
- // No trimming necessary.
- return;
- }
- mTrimDirty = false;
- mTrimmedSkPath.reset();
- if (mProperties.trimPathStart == mProperties.trimPathEnd) {
- // Trimmed path should be empty.
- return;
- }
- SkPathMeasure measure(mSkPath, false);
- float len = SkScalarToFloat(measure.getLength());
- float start = len * fmod((mProperties.trimPathStart + mProperties.trimPathOffset), 1.0f);
- float end = len * fmod((mProperties.trimPathEnd + mProperties.trimPathOffset), 1.0f);
+void FullPath::syncProperties() {
+ Path::syncProperties();
- if (start > end) {
- measure.getSegment(start, len, &mTrimmedSkPath, true);
- if (end > 0) {
- measure.getSegment(0, end, &mTrimmedSkPath, true);
- }
+ if (mStagingPropertiesDirty) {
+ mProperties.syncProperties(mStagingProperties);
} else {
- measure.getSegment(start, end, &mTrimmedSkPath, true);
+ // Update staging property with property values from animation.
+ mStagingProperties.syncProperties(mProperties);
}
+ mStagingPropertiesDirty = false;
}
-REQUIRE_COMPATIBLE_LAYOUT(FullPath::Properties);
+REQUIRE_COMPATIBLE_LAYOUT(FullPath::FullPathProperties::PrimitiveFields);
static_assert(sizeof(float) == sizeof(int32_t), "float is not the same size as int32_t");
static_assert(sizeof(SkColor) == sizeof(int32_t), "SkColor is not the same size as int32_t");
-bool FullPath::getProperties(int8_t* outProperties, int length) {
- int propertyDataSize = sizeof(Properties);
+bool FullPath::FullPathProperties::copyProperties(int8_t* outProperties, int length) const {
+ int propertyDataSize = sizeof(FullPathProperties::PrimitiveFields);
if (length != propertyDataSize) {
LOG_ALWAYS_FATAL("Properties needs exactly %d bytes, a byte array of size %d is provided",
propertyDataSize, length);
return false;
}
- Properties* out = reinterpret_cast<Properties*>(outProperties);
- *out = mProperties;
+
+ PrimitiveFields* out = reinterpret_cast<PrimitiveFields*>(outProperties);
+ *out = mPrimitiveFields;
return true;
}
-void FullPath::setColorPropertyValue(int propertyId, int32_t value) {
+void FullPath::FullPathProperties::setColorPropertyValue(int propertyId, int32_t value) {
Property currentProperty = static_cast<Property>(propertyId);
- if (currentProperty == Property::StrokeColor) {
- mProperties.strokeColor = value;
- } else if (currentProperty == Property::FillColor) {
- mProperties.fillColor = value;
+ if (currentProperty == Property::strokeColor) {
+ setStrokeColor(value);
+ } else if (currentProperty == Property::fillColor) {
+ setFillColor(value);
} else {
- LOG_ALWAYS_FATAL("Error setting color property on FullPath: No valid property with id: %d",
- propertyId);
+ LOG_ALWAYS_FATAL("Error setting color property on FullPath: No valid property"
+ " with id: %d", propertyId);
}
}
-void FullPath::setPropertyValue(int propertyId, float value) {
+void FullPath::FullPathProperties::setPropertyValue(int propertyId, float value) {
Property property = static_cast<Property>(propertyId);
switch (property) {
- case Property::StrokeWidth:
+ case Property::strokeWidth:
setStrokeWidth(value);
break;
- case Property::StrokeAlpha:
+ case Property::strokeAlpha:
setStrokeAlpha(value);
break;
- case Property::FillAlpha:
+ case Property::fillAlpha:
setFillAlpha(value);
break;
- case Property::TrimPathStart:
+ case Property::trimPathStart:
setTrimPathStart(value);
break;
- case Property::TrimPathEnd:
+ case Property::trimPathEnd:
setTrimPathEnd(value);
break;
- case Property::TrimPathOffset:
+ case Property::trimPathOffset:
setTrimPathOffset(value);
break;
default:
@@ -311,16 +309,16 @@
}
void ClipPath::drawPath(SkCanvas* outCanvas, SkPath& renderPath,
- float strokeScale, const SkMatrix& matrix){
+ float strokeScale, const SkMatrix& matrix, bool useStagingData){
outCanvas->clipPath(renderPath, SkRegion::kIntersect_Op);
}
Group::Group(const Group& group) : Node(group) {
- mProperties = group.mProperties;
+ mStagingProperties.syncProperties(group.mStagingProperties);
}
void Group::draw(SkCanvas* outCanvas, const SkMatrix& currentMatrix, float scaleX,
- float scaleY) {
+ float scaleY, bool useStagingData) {
// TODO: Try apply the matrix to the canvas instead of passing it down the tree
// Calculate current group's matrix by preConcat the parent's and
@@ -328,14 +326,15 @@
// Basically the Mfinal = Mviewport * M0 * M1 * M2;
// Mi the local matrix at level i of the group tree.
SkMatrix stackedMatrix;
- getLocalMatrix(&stackedMatrix);
+ const GroupProperties& prop = useStagingData ? mStagingProperties : mProperties;
+ getLocalMatrix(&stackedMatrix, prop);
stackedMatrix.postConcat(currentMatrix);
// Save the current clip information, which is local to this group.
outCanvas->save();
// Draw the group tree in the same order as the XML file.
for (auto& child : mChildren) {
- child->draw(outCanvas, stackedMatrix, scaleX, scaleY);
+ child->draw(outCanvas, stackedMatrix, scaleX, scaleY, useStagingData);
}
// Restore the previous clip information.
outCanvas->restore();
@@ -343,96 +342,106 @@
void Group::dump() {
ALOGD("Group %s has %zu children: ", mName.c_str(), mChildren.size());
+ ALOGD("Group translateX, Y : %f, %f, scaleX, Y: %f, %f", mProperties.getTranslateX(),
+ mProperties.getTranslateY(), mProperties.getScaleX(), mProperties.getScaleY());
for (size_t i = 0; i < mChildren.size(); i++) {
mChildren[i]->dump();
}
}
-void Group::updateLocalMatrix(float rotate, float pivotX, float pivotY,
- float scaleX, float scaleY, float translateX, float translateY) {
- setRotation(rotate);
- setPivotX(pivotX);
- setPivotY(pivotY);
- setScaleX(scaleX);
- setScaleY(scaleY);
- setTranslateX(translateX);
- setTranslateY(translateY);
+void Group::syncProperties() {
+ // Copy over the dirty staging properties
+ if (mStagingPropertiesDirty) {
+ mProperties.syncProperties(mStagingProperties);
+ } else {
+ mStagingProperties.syncProperties(mProperties);
+ }
+ mStagingPropertiesDirty = false;
+ for (auto& child : mChildren) {
+ child->syncProperties();
+ }
}
-void Group::getLocalMatrix(SkMatrix* outMatrix) {
+void Group::getLocalMatrix(SkMatrix* outMatrix, const GroupProperties& properties) {
outMatrix->reset();
// TODO: use rotate(mRotate, mPivotX, mPivotY) and scale with pivot point, instead of
// translating to pivot for rotating and scaling, then translating back.
- outMatrix->postTranslate(-mProperties.pivotX, -mProperties.pivotY);
- outMatrix->postScale(mProperties.scaleX, mProperties.scaleY);
- outMatrix->postRotate(mProperties.rotate, 0, 0);
- outMatrix->postTranslate(mProperties.translateX + mProperties.pivotX,
- mProperties.translateY + mProperties.pivotY);
+ outMatrix->postTranslate(-properties.getPivotX(), -properties.getPivotY());
+ outMatrix->postScale(properties.getScaleX(), properties.getScaleY());
+ outMatrix->postRotate(properties.getRotation(), 0, 0);
+ outMatrix->postTranslate(properties.getTranslateX() + properties.getPivotX(),
+ properties.getTranslateY() + properties.getPivotY());
}
void Group::addChild(Node* child) {
mChildren.emplace_back(child);
+ if (mPropertyChangedListener != nullptr) {
+ child->setPropertyChangedListener(mPropertyChangedListener);
+ }
}
-bool Group::getProperties(float* outProperties, int length) {
- int propertyCount = static_cast<int>(Property::Count);
+bool Group::GroupProperties::copyProperties(float* outProperties, int length) const {
+ int propertyCount = static_cast<int>(Property::count);
if (length != propertyCount) {
LOG_ALWAYS_FATAL("Properties needs exactly %d bytes, a byte array of size %d is provided",
propertyCount, length);
return false;
}
- Properties* out = reinterpret_cast<Properties*>(outProperties);
- *out = mProperties;
+
+ PrimitiveFields* out = reinterpret_cast<PrimitiveFields*>(outProperties);
+ *out = mPrimitiveFields;
return true;
}
// TODO: Consider animating the properties as float pointers
-float Group::getPropertyValue(int propertyId) const {
+// Called on render thread
+float Group::GroupProperties::getPropertyValue(int propertyId) const {
Property currentProperty = static_cast<Property>(propertyId);
switch (currentProperty) {
- case Property::Rotate:
- return mProperties.rotate;
- case Property::PivotX:
- return mProperties.pivotX;
- case Property::PivotY:
- return mProperties.pivotY;
- case Property::ScaleX:
- return mProperties.scaleX;
- case Property::ScaleY:
- return mProperties.scaleY;
- case Property::TranslateX:
- return mProperties.translateX;
- case Property::TranslateY:
- return mProperties.translateY;
+ case Property::rotate:
+ return getRotation();
+ case Property::pivotX:
+ return getPivotX();
+ case Property::pivotY:
+ return getPivotY();
+ case Property::scaleX:
+ return getScaleX();
+ case Property::scaleY:
+ return getScaleY();
+ case Property::translateX:
+ return getTranslateX();
+ case Property::translateY:
+ return getTranslateY();
default:
LOG_ALWAYS_FATAL("Invalid property index: %d", propertyId);
return 0;
}
}
-void Group::setPropertyValue(int propertyId, float value) {
+// Called on render thread
+void Group::GroupProperties::setPropertyValue(int propertyId, float value) {
Property currentProperty = static_cast<Property>(propertyId);
switch (currentProperty) {
- case Property::Rotate:
- mProperties.rotate = value;
+ case Property::rotate:
+ setRotation(value);
break;
- case Property::PivotX:
- mProperties.pivotX = value;
+ case Property::pivotX:
+ setPivotX(value);
break;
- case Property::PivotY:
- mProperties.pivotY = value;
+ case Property::pivotY:
+ setPivotY(value);
break;
- case Property::ScaleX:
- mProperties.scaleX = value;
+ case Property::scaleX:
+ setScaleX(value);
break;
- case Property::ScaleY:
- mProperties.scaleY = value;
+ case Property::scaleY:
+ setScaleY(value);
break;
- case Property::TranslateX:
- mProperties.translateX = value;
+ case Property::translateX:
+ setTranslateX(value);
break;
- case Property::TranslateY:
- mProperties.translateY = value;
+ case Property::translateY:
+ setTranslateY(value);
break;
default:
LOG_ALWAYS_FATAL("Invalid property index: %d", propertyId);
@@ -440,7 +449,11 @@
}
bool Group::isValidProperty(int propertyId) {
- return propertyId >= 0 && propertyId < static_cast<int>(Property::Count);
+ return GroupProperties::isValidProperty(propertyId);
+}
+
+bool Group::GroupProperties::isValidProperty(int propertyId) {
+ return propertyId >= 0 && propertyId < static_cast<int>(Property::count);
}
void Tree::draw(Canvas* outCanvas, SkColorFilter* colorFilter,
@@ -449,18 +462,18 @@
// avoid blurry scaling, we have to draw into a bitmap with exact pixel
// size first. This bitmap size is determined by the bounds and the
// canvas scale.
- outCanvas->getMatrix(&mCanvasMatrix);
- mBounds = bounds;
+ SkMatrix canvasMatrix;
+ outCanvas->getMatrix(&canvasMatrix);
float canvasScaleX = 1.0f;
float canvasScaleY = 1.0f;
- if (mCanvasMatrix.getSkewX() == 0 && mCanvasMatrix.getSkewY() == 0) {
+ if (canvasMatrix.getSkewX() == 0 && canvasMatrix.getSkewY() == 0) {
// Only use the scale value when there's no skew or rotation in the canvas matrix.
// TODO: Add a cts test for drawing VD on a canvas with negative scaling factors.
- canvasScaleX = fabs(mCanvasMatrix.getScaleX());
- canvasScaleY = fabs(mCanvasMatrix.getScaleY());
+ canvasScaleX = fabs(canvasMatrix.getScaleX());
+ canvasScaleY = fabs(canvasMatrix.getScaleY());
}
- int scaledWidth = (int) (mBounds.width() * canvasScaleX);
- int scaledHeight = (int) (mBounds.height() * canvasScaleY);
+ int scaledWidth = (int) (bounds.width() * canvasScaleX);
+ int scaledHeight = (int) (bounds.height() * canvasScaleY);
scaledWidth = std::min(Tree::MAX_CACHED_BITMAP_SIZE, scaledWidth);
scaledHeight = std::min(Tree::MAX_CACHED_BITMAP_SIZE, scaledHeight);
@@ -468,63 +481,105 @@
return;
}
- mPaint.setColorFilter(colorFilter);
-
+ mStagingProperties.setScaledSize(scaledWidth, scaledHeight);
int saveCount = outCanvas->save(SaveFlags::MatrixClip);
- outCanvas->translate(mBounds.fLeft, mBounds.fTop);
+ outCanvas->translate(bounds.fLeft, bounds.fTop);
// Handle RTL mirroring.
if (needsMirroring) {
- outCanvas->translate(mBounds.width(), 0);
+ outCanvas->translate(bounds.width(), 0);
outCanvas->scale(-1.0f, 1.0f);
}
+ mStagingProperties.setColorFilter(colorFilter);
// At this point, canvas has been translated to the right position.
// And we use this bound for the destination rect for the drawBitmap, so
// we offset to (0, 0);
- mBounds.offsetTo(0, 0);
- createCachedBitmapIfNeeded(scaledWidth, scaledHeight);
-
+ SkRect tmpBounds = bounds;
+ tmpBounds.offsetTo(0, 0);
+ mStagingProperties.setBounds(tmpBounds);
outCanvas->drawVectorDrawable(this);
-
outCanvas->restoreToCount(saveCount);
}
-SkPaint* Tree::getPaint() {
- SkPaint* paint;
- if (mRootAlpha == 1.0f && mPaint.getColorFilter() == NULL) {
- paint = NULL;
- } else {
- mPaint.setFilterQuality(kLow_SkFilterQuality);
- mPaint.setAlpha(mRootAlpha * 255);
- paint = &mPaint;
+void Tree::drawStaging(Canvas* outCanvas) {
+ bool redrawNeeded = allocateBitmapIfNeeded(&mStagingCache.bitmap,
+ mStagingProperties.getScaledWidth(), mStagingProperties.getScaledHeight());
+ // draw bitmap cache
+ if (redrawNeeded || mStagingCache.dirty) {
+ updateBitmapCache(&mStagingCache.bitmap, true);
+ mStagingCache.dirty = false;
}
- return paint;
+
+ SkPaint tmpPaint;
+ SkPaint* paint = updatePaint(&tmpPaint, &mStagingProperties);
+ outCanvas->drawBitmap(mStagingCache.bitmap, 0, 0,
+ mStagingCache.bitmap.width(), mStagingCache.bitmap.height(),
+ mStagingProperties.getBounds().left(), mStagingProperties.getBounds().top(),
+ mStagingProperties.getBounds().right(), mStagingProperties.getBounds().bottom(), paint);
+}
+
+SkPaint* Tree::getPaint() {
+ return updatePaint(&mPaint, &mProperties);
+}
+
+// Update the given paint with alpha and color filter. Return nullptr if no color filter is
+// specified and root alpha is 1. Otherwise, return updated paint.
+SkPaint* Tree::updatePaint(SkPaint* outPaint, TreeProperties* prop) {
+ if (prop->getRootAlpha() == 1.0f && prop->getColorFilter() == nullptr) {
+ return nullptr;
+ } else {
+ outPaint->setColorFilter(mStagingProperties.getColorFilter());
+ outPaint->setFilterQuality(kLow_SkFilterQuality);
+ outPaint->setAlpha(prop->getRootAlpha() * 255);
+ return outPaint;
+ }
}
const SkBitmap& Tree::getBitmapUpdateIfDirty() {
- mCachedBitmap.eraseColor(SK_ColorTRANSPARENT);
- SkCanvas outCanvas(mCachedBitmap);
- float scaleX = (float) mCachedBitmap.width() / mViewportWidth;
- float scaleY = (float) mCachedBitmap.height() / mViewportHeight;
- mRootNode->draw(&outCanvas, SkMatrix::I(), scaleX, scaleY);
- mCacheDirty = false;
- return mCachedBitmap;
+ bool redrawNeeded = allocateBitmapIfNeeded(&mCache.bitmap, mProperties.getScaledWidth(),
+ mProperties.getScaledHeight());
+ if (redrawNeeded || mCache.dirty) {
+ updateBitmapCache(&mCache.bitmap, false);
+ mCache.dirty = false;
+ }
+ return mCache.bitmap;
}
-void Tree::createCachedBitmapIfNeeded(int width, int height) {
- if (!canReuseBitmap(width, height)) {
+void Tree::updateBitmapCache(SkBitmap* outCache, bool useStagingData) {
+ outCache->eraseColor(SK_ColorTRANSPARENT);
+ SkCanvas outCanvas(*outCache);
+ float viewportWidth = useStagingData ?
+ mStagingProperties.getViewportWidth() : mProperties.getViewportWidth();
+ float viewportHeight = useStagingData ?
+ mStagingProperties.getViewportHeight() : mProperties.getViewportHeight();
+ float scaleX = outCache->width() / viewportWidth;
+ float scaleY = outCache->height() / viewportHeight;
+ mRootNode->draw(&outCanvas, SkMatrix::I(), scaleX, scaleY, useStagingData);
+}
+
+bool Tree::allocateBitmapIfNeeded(SkBitmap* outCache, int width, int height) {
+ if (!canReuseBitmap(*outCache, width, height)) {
SkImageInfo info = SkImageInfo::Make(width, height,
kN32_SkColorType, kPremul_SkAlphaType);
- mCachedBitmap.setInfo(info);
+ outCache->setInfo(info);
// TODO: Count the bitmap cache against app's java heap
- mCachedBitmap.allocPixels(info);
- mCacheDirty = true;
+ outCache->allocPixels(info);
+ return true;
}
+ return false;
}
-bool Tree::canReuseBitmap(int width, int height) {
- return width == mCachedBitmap.width() && height == mCachedBitmap.height();
+bool Tree::canReuseBitmap(const SkBitmap& bitmap, int width, int height) {
+ return width == bitmap.width() && height == bitmap.height();
+}
+
+void Tree::onPropertyChanged(TreeProperties* prop) {
+ if (prop == &mStagingProperties) {
+ mStagingCache.dirty = true;
+ } else {
+ mCache.dirty = true;
+ }
}
}; // namespace VectorDrawable
diff --git a/libs/hwui/VectorDrawable.h b/libs/hwui/VectorDrawable.h
index 7a45bf5..e4c7ed7 100644
--- a/libs/hwui/VectorDrawable.h
+++ b/libs/hwui/VectorDrawable.h
@@ -18,9 +18,11 @@
#define ANDROID_HWUI_VPATH_H
#include "hwui/Canvas.h"
+#include "DisplayList.h"
#include <SkBitmap.h>
#include <SkColor.h>
+#include <SkColorFilter.h>
#include <SkCanvas.h>
#include <SkMatrix.h>
#include <SkPaint.h>
@@ -38,8 +40,11 @@
namespace uirenderer {
namespace VectorDrawable {
-#define VD_SET_PROP_WITH_FLAG(field, value, flag) (VD_SET_PROP(field, value) ? (flag = true, true): false);
+#define VD_SET_PROP_WITH_FLAG(field, value, flag) (VD_SET_PROP_AND_NOTIFY(field, value) ? (flag = true, true) : false)
#define VD_SET_PROP(field, value) (value != field ? (field = value, true) : false)
+#define VD_SET_PROP_AND_NOTIFY(field, value) ({ bool retVal = VD_SET_PROP(field, value);\
+ onPropertyChanged(); retVal;})
+#define UPDATE_SKPROP(field, value) ({bool retVal = (field != value); if (field != value) SkRefCnt_SafeAssign(field, value); retVal;})
/* A VectorDrawable is composed of a tree of nodes.
* Each node can be a group node, or a path.
@@ -52,22 +57,65 @@
* / \ |
* Path Path Path
*
+ * VectorDrawables are drawn into bitmap caches first, then the caches are drawn to the given
+ * canvas with root alpha applied. Two caches are maintained for VD, one in UI thread, the other in
+ * Render Thread. A generation id is used to keep track of changes in the vector drawable tree.
+ * Each cache has their own generation id to track whether they are up to date with the latest
+ * change in the tree.
+ *
+ * Any property change to the vector drawable coming from UI thread (such as bulk setters to update
+ * all the properties, and viewport change, etc.) are only modifying the staging properties. The
+ * staging properties will then be marked dirty and will be pushed over to render thread properties
+ * at sync point. If staging properties are not dirty at sync point, we sync backwards by updating
+ * staging properties with render thread properties to reflect the latest animation value.
+ *
*/
+
+class PropertyChangedListener {
+public:
+ PropertyChangedListener(bool* dirty, bool* stagingDirty)
+ : mDirty(dirty), mStagingDirty(stagingDirty) {}
+ void onPropertyChanged() {
+ *mDirty = true;
+ }
+ void onStagingPropertyChanged() {
+ *mStagingDirty = true;
+ }
+private:
+ bool* mDirty;
+ bool* mStagingDirty;
+};
+
class ANDROID_API Node {
public:
+ class Properties {
+ public:
+ Properties(Node* node) : mNode(node) {}
+ inline void onPropertyChanged() {
+ mNode->onPropertyChanged(this);
+ }
+ private:
+ Node* mNode;
+ };
Node(const Node& node) {
mName = node.mName;
}
Node() {}
virtual void draw(SkCanvas* outCanvas, const SkMatrix& currentMatrix,
- float scaleX, float scaleY) = 0;
+ float scaleX, float scaleY, bool useStagingData) = 0;
virtual void dump() = 0;
void setName(const char* name) {
mName = name;
}
+ virtual void setPropertyChangedListener(PropertyChangedListener* listener) {
+ mPropertyChangedListener = listener;
+ }
+ virtual void onPropertyChanged(Properties* properties) = 0;
virtual ~Node(){}
+ virtual void syncProperties() = 0;
protected:
std::string mName;
+ PropertyChangedListener* mPropertyChangedListener = nullptr;
};
class ANDROID_API Path : public Node {
@@ -81,150 +129,267 @@
&& points == data.points;
}
};
- Path(const Data& nodes);
+
+ class PathProperties : public Properties {
+ public:
+ PathProperties(Node* node) : Properties(node) {}
+ void syncProperties(const PathProperties& prop) {
+ mData = prop.mData;
+ onPropertyChanged();
+ }
+ void setData(const Data& data) {
+ // Updates the path data. Note that we don't generate a new Skia path right away
+ // because there are cases where the animation is changing the path data, but the view
+ // that hosts the VD has gone off screen, in which case we won't even draw. So we
+ // postpone the Skia path generation to the draw time.
+ if (data == mData) {
+ return;
+ }
+ mData = data;
+ onPropertyChanged();
+
+ }
+ const Data& getData() const {
+ return mData;
+ }
+ private:
+ Data mData;
+ };
+
Path(const Path& path);
Path(const char* path, size_t strLength);
Path() {}
+
void dump() override;
- bool canMorph(const Data& path);
- bool canMorph(const Path& path);
void draw(SkCanvas* outCanvas, const SkMatrix& groupStackedMatrix,
- float scaleX, float scaleY) override;
- void setPath(const char* path, size_t strLength);
- void setPathData(const Data& data);
+ float scaleX, float scaleY, bool useStagingData) override;
static float getMatrixScale(const SkMatrix& groupStackedMatrix);
+ virtual void syncProperties() override;
+ virtual void onPropertyChanged(Properties* prop) override {
+ if (prop == &mStagingProperties) {
+ mStagingPropertiesDirty = true;
+ if (mPropertyChangedListener) {
+ mPropertyChangedListener->onStagingPropertyChanged();
+ }
+ } else if (prop == &mProperties){
+ mSkPathDirty = true;
+ if (mPropertyChangedListener) {
+ mPropertyChangedListener->onPropertyChanged();
+ }
+ }
+ }
+ PathProperties* mutateStagingProperties() { return &mStagingProperties; }
+ const PathProperties* stagingProperties() { return &mStagingProperties; }
+
+ // This should only be called from animations on RT
+ PathProperties* mutateProperties() { return &mProperties; }
protected:
virtual const SkPath& getUpdatedPath();
+ virtual void getStagingPath(SkPath* outPath);
virtual void drawPath(SkCanvas *outCanvas, SkPath& renderPath,
- float strokeScale, const SkMatrix& matrix) = 0;
- Data mData;
- SkPath mSkPath;
+ float strokeScale, const SkMatrix& matrix, bool useStagingData) = 0;
+
+ // Internal data, render thread only.
bool mSkPathDirty = true;
+ SkPath mSkPath;
+
+private:
+ PathProperties mProperties = PathProperties(this);
+ PathProperties mStagingProperties = PathProperties(this);
+ bool mStagingPropertiesDirty = true;
};
class ANDROID_API FullPath: public Path {
public:
+ class FullPathProperties : public Properties {
+ public:
+ struct PrimitiveFields {
+ float strokeWidth = 0;
+ SkColor strokeColor = SK_ColorTRANSPARENT;
+ float strokeAlpha = 1;
+ SkColor fillColor = SK_ColorTRANSPARENT;
+ float fillAlpha = 1;
+ float trimPathStart = 0;
+ float trimPathEnd = 1;
+ float trimPathOffset = 0;
+ int32_t strokeLineCap = SkPaint::Cap::kButt_Cap;
+ int32_t strokeLineJoin = SkPaint::Join::kMiter_Join;
+ float strokeMiterLimit = 4;
+ int fillType = 0; /* non-zero or kWinding_FillType in Skia */
+ };
+ FullPathProperties(Node* mNode) : Properties(mNode), mTrimDirty(false) {}
+ void syncProperties(const FullPathProperties& prop) {
+ mPrimitiveFields = prop.mPrimitiveFields;
+ mTrimDirty = true;
+ fillGradient.reset(prop.fillGradient);
+ strokeGradient.reset(prop.strokeGradient);
+ onPropertyChanged();
+ }
+ void setFillGradient(SkShader* gradient) {
+ if(fillGradient != gradient){
+ fillGradient.reset(gradient);
+ onPropertyChanged();
+ }
+ }
+ void setStrokeGradient(SkShader* gradient) {
+ if(strokeGradient != gradient){
+ strokeGradient.reset(gradient);
+ onPropertyChanged();
+ }
+ }
+ SkShader* getFillGradient() const {
+ return fillGradient;
+ }
+ SkShader* getStrokeGradient() const {
+ return strokeGradient;
+ }
+ float getStrokeWidth() const{
+ return mPrimitiveFields.strokeWidth;
+ }
+ void setStrokeWidth(float strokeWidth) {
+ VD_SET_PROP_AND_NOTIFY(strokeWidth, strokeWidth);
+ }
+ SkColor getStrokeColor() const{
+ return mPrimitiveFields.strokeColor;
+ }
+ void setStrokeColor(SkColor strokeColor) {
+ VD_SET_PROP_AND_NOTIFY(mPrimitiveFields.strokeColor, strokeColor);
+ }
+ float getStrokeAlpha() const{
+ return mPrimitiveFields.strokeAlpha;
+ }
+ void setStrokeAlpha(float strokeAlpha) {
+ VD_SET_PROP_AND_NOTIFY(mPrimitiveFields.strokeAlpha, strokeAlpha);
+ }
+ SkColor getFillColor() const {
+ return mPrimitiveFields.fillColor;
+ }
+ void setFillColor(SkColor fillColor) {
+ VD_SET_PROP_AND_NOTIFY(mPrimitiveFields.fillColor, fillColor);
+ }
+ float getFillAlpha() const{
+ return mPrimitiveFields.fillAlpha;
+ }
+ void setFillAlpha(float fillAlpha) {
+ VD_SET_PROP_AND_NOTIFY(mPrimitiveFields.fillAlpha, fillAlpha);
+ }
+ float getTrimPathStart() const{
+ return mPrimitiveFields.trimPathStart;
+ }
+ void setTrimPathStart(float trimPathStart) {
+ VD_SET_PROP_WITH_FLAG(mPrimitiveFields.trimPathStart, trimPathStart, mTrimDirty);
+ }
+ float getTrimPathEnd() const{
+ return mPrimitiveFields.trimPathEnd;
+ }
+ void setTrimPathEnd(float trimPathEnd) {
+ VD_SET_PROP_WITH_FLAG(mPrimitiveFields.trimPathEnd, trimPathEnd, mTrimDirty);
+ }
+ float getTrimPathOffset() const{
+ return mPrimitiveFields.trimPathOffset;
+ }
+ void setTrimPathOffset(float trimPathOffset) {
+ VD_SET_PROP_WITH_FLAG(mPrimitiveFields.trimPathOffset, trimPathOffset, mTrimDirty);
+ }
-struct Properties {
- float strokeWidth = 0;
- SkColor strokeColor = SK_ColorTRANSPARENT;
- float strokeAlpha = 1;
- SkColor fillColor = SK_ColorTRANSPARENT;
- float fillAlpha = 1;
- float trimPathStart = 0;
- float trimPathEnd = 1;
- float trimPathOffset = 0;
- int32_t strokeLineCap = SkPaint::Cap::kButt_Cap;
- int32_t strokeLineJoin = SkPaint::Join::kMiter_Join;
- float strokeMiterLimit = 4;
- int fillType = 0; /* non-zero or kWinding_FillType in Skia */
-};
+ float getStrokeMiterLimit() const {
+ return mPrimitiveFields.strokeMiterLimit;
+ }
+ float getStrokeLineCap() const {
+ return mPrimitiveFields.strokeLineCap;
+ }
+ float getStrokeLineJoin() const {
+ return mPrimitiveFields.strokeLineJoin;
+ }
+ float getFillType() const {
+ return mPrimitiveFields.fillType;
+ }
+ bool copyProperties(int8_t* outProperties, int length) const;
+ void updateProperties(float strokeWidth, SkColor strokeColor, float strokeAlpha,
+ SkColor fillColor, float fillAlpha, float trimPathStart, float trimPathEnd,
+ float trimPathOffset, float strokeMiterLimit, int strokeLineCap, int strokeLineJoin,
+ int fillType) {
+ mPrimitiveFields.strokeWidth = strokeWidth;
+ mPrimitiveFields.strokeColor = strokeColor;
+ mPrimitiveFields.strokeAlpha = strokeAlpha;
+ mPrimitiveFields.fillColor = fillColor;
+ mPrimitiveFields.fillAlpha = fillAlpha;
+ mPrimitiveFields.trimPathStart = trimPathStart;
+ mPrimitiveFields.trimPathEnd = trimPathEnd;
+ mPrimitiveFields.trimPathOffset = trimPathOffset;
+ mPrimitiveFields.strokeMiterLimit = strokeMiterLimit;
+ mPrimitiveFields.strokeLineCap = strokeLineCap;
+ mPrimitiveFields.strokeLineJoin = strokeLineJoin;
+ mPrimitiveFields.fillType = fillType;
+ mTrimDirty = true;
+ onPropertyChanged();
+ }
+ // Set property values during animation
+ void setColorPropertyValue(int propertyId, int32_t value);
+ void setPropertyValue(int propertyId, float value);
+ bool mTrimDirty;
+ private:
+ enum class Property {
+ strokeWidth = 0,
+ strokeColor,
+ strokeAlpha,
+ fillColor,
+ fillAlpha,
+ trimPathStart,
+ trimPathEnd,
+ trimPathOffset,
+ strokeLineCap,
+ strokeLineJoin,
+ strokeMiterLimit,
+ fillType,
+ count,
+ };
+ PrimitiveFields mPrimitiveFields;
+ SkAutoTUnref<SkShader> fillGradient;
+ SkAutoTUnref<SkShader> strokeGradient;
+ };
+ // Called from UI thread
FullPath(const FullPath& path); // for cloning
FullPath(const char* path, size_t strLength) : Path(path, strLength) {}
FullPath() : Path() {}
- FullPath(const Data& nodes) : Path(nodes) {}
+ void dump() override;
+ FullPathProperties* mutateStagingProperties() { return &mStagingProperties; }
+ const FullPathProperties* stagingProperties() { return &mStagingProperties; }
- ~FullPath() {
- SkSafeUnref(mFillGradient);
- SkSafeUnref(mStrokeGradient);
- }
+ // This should only be called from animations on RT
+ FullPathProperties* mutateProperties() { return &mProperties; }
- void updateProperties(float strokeWidth, SkColor strokeColor,
- float strokeAlpha, SkColor fillColor, float fillAlpha,
- float trimPathStart, float trimPathEnd, float trimPathOffset,
- float strokeMiterLimit, int strokeLineCap, int strokeLineJoin, int fillType);
- // TODO: Cleanup: Remove the setter and getters below, and their counterparts in java and JNI
- float getStrokeWidth() {
- return mProperties.strokeWidth;
+ virtual void syncProperties() override;
+ virtual void onPropertyChanged(Properties* properties) override {
+ Path::onPropertyChanged(properties);
+ if (properties == &mStagingProperties) {
+ mStagingPropertiesDirty = true;
+ if (mPropertyChangedListener) {
+ mPropertyChangedListener->onStagingPropertyChanged();
+ }
+ } else if (properties == &mProperties) {
+ if (mPropertyChangedListener) {
+ mPropertyChangedListener->onPropertyChanged();
+ }
+ }
}
- void setStrokeWidth(float strokeWidth) {
- mProperties.strokeWidth = strokeWidth;
- }
- SkColor getStrokeColor() {
- return mProperties.strokeColor;
- }
- void setStrokeColor(SkColor strokeColor) {
- mProperties.strokeColor = strokeColor;
- }
- float getStrokeAlpha() {
- return mProperties.strokeAlpha;
- }
- void setStrokeAlpha(float strokeAlpha) {
- mProperties.strokeAlpha = strokeAlpha;
- }
- SkColor getFillColor() {
- return mProperties.fillColor;
- }
- void setFillColor(SkColor fillColor) {
- mProperties.fillColor = fillColor;
- }
- float getFillAlpha() {
- return mProperties.fillAlpha;
- }
- void setFillAlpha(float fillAlpha) {
- mProperties.fillAlpha = fillAlpha;
- }
- float getTrimPathStart() {
- return mProperties.trimPathStart;
- }
- void setTrimPathStart(float trimPathStart) {
- VD_SET_PROP_WITH_FLAG(mProperties.trimPathStart, trimPathStart, mTrimDirty);
- }
- float getTrimPathEnd() {
- return mProperties.trimPathEnd;
- }
- void setTrimPathEnd(float trimPathEnd) {
- VD_SET_PROP_WITH_FLAG(mProperties.trimPathEnd, trimPathEnd, mTrimDirty);
- }
- float getTrimPathOffset() {
- return mProperties.trimPathOffset;
- }
- void setTrimPathOffset(float trimPathOffset) {
- VD_SET_PROP_WITH_FLAG(mProperties.trimPathOffset, trimPathOffset, mTrimDirty);
- }
- bool getProperties(int8_t* outProperties, int length);
- void setColorPropertyValue(int propertyId, int32_t value);
- void setPropertyValue(int propertyId, float value);
-
- void setFillGradient(SkShader* fillGradient) {
- SkRefCnt_SafeAssign(mFillGradient, fillGradient);
- };
- void setStrokeGradient(SkShader* strokeGradient) {
- SkRefCnt_SafeAssign(mStrokeGradient, strokeGradient);
- };
-
protected:
const SkPath& getUpdatedPath() override;
+ void getStagingPath(SkPath* outPath) override;
void drawPath(SkCanvas* outCanvas, SkPath& renderPath,
- float strokeScale, const SkMatrix& matrix) override;
-
+ float strokeScale, const SkMatrix& matrix, bool useStagingData) override;
private:
- enum class Property {
- StrokeWidth = 0,
- StrokeColor,
- StrokeAlpha,
- FillColor,
- FillAlpha,
- TrimPathStart,
- TrimPathEnd,
- TrimPathOffset,
- StrokeLineCap,
- StrokeLineJoin,
- StrokeMiterLimit,
- FillType,
- Count,
- };
- // Applies trimming to the specified path.
- void applyTrim();
- Properties mProperties;
- bool mTrimDirty = true;
+
+ FullPathProperties mProperties = FullPathProperties(this);
+ FullPathProperties mStagingProperties = FullPathProperties(this);
+ bool mStagingPropertiesDirty = true;
+
+ // Intermediate data for drawing, render thread only
SkPath mTrimmedSkPath;
- SkPaint mPaint;
- SkShader* mStrokeGradient = nullptr;
- SkShader* mFillGradient = nullptr;
+
};
class ANDROID_API ClipPath: public Path {
@@ -232,143 +397,316 @@
ClipPath(const ClipPath& path) : Path(path) {}
ClipPath(const char* path, size_t strLength) : Path(path, strLength) {}
ClipPath() : Path() {}
- ClipPath(const Data& nodes) : Path(nodes) {}
protected:
void drawPath(SkCanvas* outCanvas, SkPath& renderPath,
- float strokeScale, const SkMatrix& matrix) override;
+ float strokeScale, const SkMatrix& matrix, bool useStagingData) override;
};
class ANDROID_API Group: public Node {
public:
- struct Properties {
- float rotate = 0;
- float pivotX = 0;
- float pivotY = 0;
- float scaleX = 1;
- float scaleY = 1;
- float translateX = 0;
- float translateY = 0;
+ class GroupProperties : public Properties {
+ public:
+ GroupProperties(Node* mNode) : Properties(mNode) {}
+ struct PrimitiveFields {
+ float rotate = 0;
+ float pivotX = 0;
+ float pivotY = 0;
+ float scaleX = 1;
+ float scaleY = 1;
+ float translateX = 0;
+ float translateY = 0;
+ } mPrimitiveFields;
+ void syncProperties(const GroupProperties& prop) {
+ mPrimitiveFields = prop.mPrimitiveFields;
+ onPropertyChanged();
+ }
+ float getRotation() const {
+ return mPrimitiveFields.rotate;
+ }
+ void setRotation(float rotation) {
+ VD_SET_PROP_AND_NOTIFY(mPrimitiveFields.rotate, rotation);
+ }
+ float getPivotX() const {
+ return mPrimitiveFields.pivotX;
+ }
+ void setPivotX(float pivotX) {
+ VD_SET_PROP_AND_NOTIFY(mPrimitiveFields.pivotX, pivotX);
+ }
+ float getPivotY() const {
+ return mPrimitiveFields.pivotY;
+ }
+ void setPivotY(float pivotY) {
+ VD_SET_PROP_AND_NOTIFY(mPrimitiveFields.pivotY, pivotY);
+ }
+ float getScaleX() const {
+ return mPrimitiveFields.scaleX;
+ }
+ void setScaleX(float scaleX) {
+ VD_SET_PROP_AND_NOTIFY(mPrimitiveFields.scaleX, scaleX);
+ }
+ float getScaleY() const {
+ return mPrimitiveFields.scaleY;
+ }
+ void setScaleY(float scaleY) {
+ VD_SET_PROP_AND_NOTIFY(mPrimitiveFields.scaleY, scaleY);
+ }
+ float getTranslateX() const {
+ return mPrimitiveFields.translateX;
+ }
+ void setTranslateX(float translateX) {
+ VD_SET_PROP_AND_NOTIFY(mPrimitiveFields.translateX, translateX);
+ }
+ float getTranslateY() const {
+ return mPrimitiveFields.translateY;
+ }
+ void setTranslateY(float translateY) {
+ VD_SET_PROP_AND_NOTIFY(translateY, translateY);
+ }
+ void updateProperties(float rotate, float pivotX, float pivotY,
+ float scaleX, float scaleY, float translateX, float translateY) {
+ mPrimitiveFields.rotate = rotate;
+ mPrimitiveFields.pivotX = pivotX;
+ mPrimitiveFields.pivotY = pivotY;
+ mPrimitiveFields.scaleX = scaleX;
+ mPrimitiveFields.scaleY = scaleY;
+ mPrimitiveFields.translateX = translateX;
+ mPrimitiveFields.translateY = translateY;
+ onPropertyChanged();
+ }
+ void setPropertyValue(int propertyId, float value);
+ float getPropertyValue(int propertyId) const;
+ bool copyProperties(float* outProperties, int length) const;
+ static bool isValidProperty(int propertyId);
+ private:
+ enum class Property {
+ rotate = 0,
+ pivotX,
+ pivotY,
+ scaleX,
+ scaleY,
+ translateX,
+ translateY,
+ // Count of the properties, must be at the end.
+ count,
+ };
};
+
Group(const Group& group);
Group() {}
- float getRotation() {
- return mProperties.rotate;
- }
- void setRotation(float rotation) {
- mProperties.rotate = rotation;
- }
- float getPivotX() {
- return mProperties.pivotX;
- }
- void setPivotX(float pivotX) {
- mProperties.pivotX = pivotX;
- }
- float getPivotY() {
- return mProperties.pivotY;
- }
- void setPivotY(float pivotY) {
- mProperties.pivotY = pivotY;
- }
- float getScaleX() {
- return mProperties.scaleX;
- }
- void setScaleX(float scaleX) {
- mProperties.scaleX = scaleX;
- }
- float getScaleY() {
- return mProperties.scaleY;
- }
- void setScaleY(float scaleY) {
- mProperties.scaleY = scaleY;
- }
- float getTranslateX() {
- return mProperties.translateX;
- }
- void setTranslateX(float translateX) {
- mProperties.translateX = translateX;
- }
- float getTranslateY() {
- return mProperties.translateY;
- }
- void setTranslateY(float translateY) {
- mProperties.translateY = translateY;
- }
- virtual void draw(SkCanvas* outCanvas, const SkMatrix& currentMatrix,
- float scaleX, float scaleY) override;
- void updateLocalMatrix(float rotate, float pivotX, float pivotY,
- float scaleX, float scaleY, float translateX, float translateY);
- void getLocalMatrix(SkMatrix* outMatrix);
void addChild(Node* child);
+ virtual void setPropertyChangedListener(PropertyChangedListener* listener) override {
+ Node::setPropertyChangedListener(listener);
+ for (auto& child : mChildren) {
+ child->setPropertyChangedListener(listener);
+ }
+ }
+ virtual void syncProperties() override;
+ GroupProperties* mutateStagingProperties() { return &mStagingProperties; }
+ const GroupProperties* stagingProperties() { return &mStagingProperties; }
+
+ // This should only be called from animations on RT
+ GroupProperties* mutateProperties() { return &mProperties; }
+
+ // Methods below could be called from either UI thread or Render Thread.
+ virtual void draw(SkCanvas* outCanvas, const SkMatrix& currentMatrix,
+ float scaleX, float scaleY, bool useStagingData) override;
+ void getLocalMatrix(SkMatrix* outMatrix, const GroupProperties& properties);
void dump() override;
- bool getProperties(float* outProperties, int length);
- float getPropertyValue(int propertyId) const;
- void setPropertyValue(int propertyId, float value);
static bool isValidProperty(int propertyId);
+ virtual void onPropertyChanged(Properties* properties) override {
+ if (properties == &mStagingProperties) {
+ mStagingPropertiesDirty = true;
+ if (mPropertyChangedListener) {
+ mPropertyChangedListener->onStagingPropertyChanged();
+ }
+ } else {
+ if (mPropertyChangedListener) {
+ mPropertyChangedListener->onPropertyChanged();
+ }
+ }
+ }
+
private:
- enum class Property {
- Rotate = 0,
- PivotX,
- PivotY,
- ScaleX,
- ScaleY,
- TranslateX,
- TranslateY,
- // Count of the properties, must be at the end.
- Count,
- };
+ GroupProperties mProperties = GroupProperties(this);
+ GroupProperties mStagingProperties = GroupProperties(this);
+ bool mStagingPropertiesDirty = true;
std::vector< std::unique_ptr<Node> > mChildren;
- Properties mProperties;
};
class ANDROID_API Tree : public VirtualLightRefBase {
public:
- Tree(Group* rootNode) : mRootNode(rootNode) {}
+ Tree(Group* rootNode) : mRootNode(rootNode) {
+ mRootNode->setPropertyChangedListener(&mPropertyChangedListener);
+ }
void draw(Canvas* outCanvas, SkColorFilter* colorFilter,
const SkRect& bounds, bool needsMirroring, bool canReuseCache);
+ void drawStaging(Canvas* canvas);
const SkBitmap& getBitmapUpdateIfDirty();
- void createCachedBitmapIfNeeded(int width, int height);
- bool canReuseBitmap(int width, int height);
void setAllowCaching(bool allowCaching) {
mAllowCaching = allowCaching;
}
- bool setRootAlpha(float rootAlpha) {
- return VD_SET_PROP(mRootAlpha, rootAlpha);
+ SkPaint* getPaint();
+ void syncProperties() {
+ if (mStagingProperties.mNonAnimatablePropertiesDirty) {
+ mProperties.syncNonAnimatableProperties(mStagingProperties);
+ mStagingProperties.mNonAnimatablePropertiesDirty = false;
+ }
+
+ if (mStagingProperties.mAnimatablePropertiesDirty) {
+ mProperties.syncAnimatableProperties(mStagingProperties);
+ } else {
+ mStagingProperties.syncAnimatableProperties(mProperties);
+ }
+ mStagingProperties.mAnimatablePropertiesDirty = false;
+ mRootNode->syncProperties();
}
- float getRootAlpha() {
- return mRootAlpha;
- }
- void setViewportSize(float viewportWidth, float viewportHeight) {
- mViewportWidth = viewportWidth;
- mViewportHeight = viewportHeight;
- }
- SkPaint* getPaint();
- const SkRect& getBounds() const {
- return mBounds;
- }
+ class TreeProperties {
+ public:
+ TreeProperties(Tree* tree) : mTree(tree) {}
+ // Properties that can only be modified by UI thread, therefore sync should
+ // only go from UI to RT
+ struct NonAnimatableProperties {
+ float viewportWidth = 0;
+ float viewportHeight = 0;
+ SkRect bounds;
+ int scaledWidth = 0;
+ int scaledHeight = 0;
+ SkColorFilter* colorFilter = nullptr;
+ ~NonAnimatableProperties() {
+ SkSafeUnref(colorFilter);
+ }
+ } mNonAnimatableProperties;
+ bool mNonAnimatablePropertiesDirty = true;
+
+ float mRootAlpha = 1.0f;
+ bool mAnimatablePropertiesDirty = true;
+
+ void syncNonAnimatableProperties(const TreeProperties& prop) {
+ // Copy over the data that can only be changed in UI thread
+ if (mNonAnimatableProperties.colorFilter != prop.mNonAnimatableProperties.colorFilter) {
+ SkRefCnt_SafeAssign(mNonAnimatableProperties.colorFilter,
+ prop.mNonAnimatableProperties.colorFilter);
+ }
+ mNonAnimatableProperties = prop.mNonAnimatableProperties;
+ }
+
+ void setViewportSize(float width, float height) {
+ if (mNonAnimatableProperties.viewportWidth != width
+ || mNonAnimatableProperties.viewportHeight != height) {
+ mNonAnimatablePropertiesDirty = true;
+ mNonAnimatableProperties.viewportWidth = width;
+ mNonAnimatableProperties.viewportHeight = height;
+ mTree->onPropertyChanged(this);
+ }
+ }
+ void setBounds(const SkRect& bounds) {
+ if (mNonAnimatableProperties.bounds != bounds) {
+ mNonAnimatableProperties.bounds = bounds;
+ mNonAnimatablePropertiesDirty = true;
+ mTree->onPropertyChanged(this);
+ }
+ }
+
+ void setScaledSize(int width, int height) {
+ if (mNonAnimatableProperties.scaledWidth != width
+ || mNonAnimatableProperties.scaledHeight != height) {
+ mNonAnimatableProperties.scaledWidth = width;
+ mNonAnimatableProperties.scaledHeight = height;
+ mNonAnimatablePropertiesDirty = true;
+ mTree->onPropertyChanged(this);
+ }
+ }
+ void setColorFilter(SkColorFilter* filter) {
+ if (UPDATE_SKPROP(mNonAnimatableProperties.colorFilter, filter)) {
+ mNonAnimatablePropertiesDirty = true;
+ mTree->onPropertyChanged(this);
+ }
+ }
+ SkColorFilter* getColorFilter() const{
+ return mNonAnimatableProperties.colorFilter;
+ }
+
+ float getViewportWidth() const {
+ return mNonAnimatableProperties.viewportWidth;
+ }
+ float getViewportHeight() const {
+ return mNonAnimatableProperties.viewportHeight;
+ }
+ float getScaledWidth() const {
+ return mNonAnimatableProperties.scaledWidth;
+ }
+ float getScaledHeight() const {
+ return mNonAnimatableProperties.scaledHeight;
+ }
+ void syncAnimatableProperties(const TreeProperties& prop) {
+ mRootAlpha = prop.mRootAlpha;
+ }
+ bool setRootAlpha(float rootAlpha) {
+ if (rootAlpha != mRootAlpha) {
+ mAnimatablePropertiesDirty = true;
+ mRootAlpha = rootAlpha;
+ mTree->onPropertyChanged(this);
+ return true;
+ }
+ return false;
+ }
+ float getRootAlpha() const { return mRootAlpha;}
+ const SkRect& getBounds() const {
+ return mNonAnimatableProperties.bounds;
+ }
+ Tree* mTree;
+ };
+ void onPropertyChanged(TreeProperties* prop);
+ TreeProperties* mutateStagingProperties() { return &mStagingProperties; }
+ const TreeProperties* stagingProperties() { return &mStagingProperties; }
+ PushStagingFunctor* getFunctor() { return &mFunctor;}
+
+ // This should only be called from animations on RT
+ TreeProperties* mutateProperties() { return &mProperties; }
private:
+ class VectorDrawableFunctor : public PushStagingFunctor {
+ public:
+ VectorDrawableFunctor(Tree* tree) : mTree(tree) {}
+ virtual void operator ()() {
+ mTree->syncProperties();
+ }
+ private:
+ Tree* mTree;
+ };
+
+ SkPaint* updatePaint(SkPaint* outPaint, TreeProperties* prop);
+ bool allocateBitmapIfNeeded(SkBitmap* outCache, int width, int height);
+ bool canReuseBitmap(const SkBitmap&, int width, int height);
+ void updateBitmapCache(SkBitmap* outCache, bool useStagingData);
// Cap the bitmap size, such that it won't hurt the performance too much
// and it won't crash due to a very large scale.
// The drawable will look blurry above this size.
const static int MAX_CACHED_BITMAP_SIZE;
- bool mCacheDirty = true;
bool mAllowCaching = true;
- float mViewportWidth = 0;
- float mViewportHeight = 0;
- float mRootAlpha = 1.0f;
-
std::unique_ptr<Group> mRootNode;
- SkRect mBounds;
- SkMatrix mCanvasMatrix;
- SkPaint mPaint;
- SkPathMeasure mPathMeasure;
- SkBitmap mCachedBitmap;
+ TreeProperties mProperties = TreeProperties(this);
+ TreeProperties mStagingProperties = TreeProperties(this);
+
+ VectorDrawableFunctor mFunctor = VectorDrawableFunctor(this);
+
+ SkPaint mPaint;
+ struct Cache {
+ SkBitmap bitmap;
+ bool dirty = true;
+ };
+
+ Cache mStagingCache;
+ Cache mCache;
+
+ PropertyChangedListener mPropertyChangedListener
+ = PropertyChangedListener(&mCache.dirty, &mStagingCache.dirty);
};
} // namespace VectorDrawable
diff --git a/libs/hwui/font/Font.cpp b/libs/hwui/font/Font.cpp
index 9a825fd..8e04c87 100644
--- a/libs/hwui/font/Font.cpp
+++ b/libs/hwui/font/Font.cpp
@@ -356,8 +356,6 @@
}
void Font::precache(const SkPaint* paint, const glyph_t* glyphs, int numGlyphs) {
- ATRACE_NAME("Precache Glyphs");
-
if (numGlyphs == 0 || glyphs == nullptr) {
return;
}
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index eee5278..63fa788 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -86,10 +86,12 @@
freePrefetechedLayers();
destroyHardwareResources();
mAnimationContext->destroy();
+#if !HWUI_NEW_OPS
if (mCanvas) {
delete mCanvas;
mCanvas = nullptr;
}
+#endif
}
void CanvasContext::setSurface(Surface* surface) {
@@ -574,7 +576,7 @@
static void destroyPrefetechedNode(RenderNode* node) {
ALOGW("Incorrectly called buildLayer on View: %s, destroying layer...", node->getName());
- node->destroyHardwareResources();
+ node->destroyHardwareResources(nullptr);
node->decStrong(nullptr);
}
@@ -587,9 +589,11 @@
void CanvasContext::buildLayer(RenderNode* node) {
ATRACE_CALL();
- if (!mEglManager.hasEglContext() || !mCanvas) {
- return;
- }
+ if (!mEglManager.hasEglContext()) return;
+#if !HWUI_NEW_OPS
+ if (!mCanvas) return;
+#endif
+
// buildLayer() will leave the tree in an unknown state, so we must stop drawing
stopDrawing();
@@ -609,7 +613,15 @@
node->setPropertyFieldsDirty(RenderNode::GENERIC);
#if HWUI_NEW_OPS
- // TODO: support buildLayer
+ static const std::vector< sp<RenderNode> > emptyNodeList;
+ auto& caches = Caches::getInstance();
+ FrameBuilder frameBuilder(mLayerUpdateQueue, SkRect::MakeWH(1, 1), 1, 1,
+ emptyNodeList, mLightGeometry, mContentDrawBounds, caches);
+ mLayerUpdateQueue.clear();
+ BakedOpRenderer renderer(caches, mRenderThread.renderState(),
+ mOpaque, mLightInfo);
+ LOG_ALWAYS_FATAL_IF(renderer.didDraw(), "shouldn't draw in buildlayer case");
+ frameBuilder.replayBakedOps<BakedOpDispatcher>(renderer);
#else
mCanvas->markLayersAsBuildLayers();
mCanvas->flushLayerUpdates();
@@ -629,7 +641,7 @@
if (mEglManager.hasEglContext()) {
freePrefetechedLayers();
for (const sp<RenderNode>& node : mRenderNodes) {
- node->destroyHardwareResources();
+ node->destroyHardwareResources(nullptr);
}
Caches& caches = Caches::getInstance();
// Make sure to release all the textures we were owning as there won't
diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h
index 6706c30..6d0889e 100644
--- a/libs/hwui/renderthread/CanvasContext.h
+++ b/libs/hwui/renderthread/CanvasContext.h
@@ -196,10 +196,11 @@
RingBuffer<SwapHistory, 3> mSwapHistory;
bool mOpaque;
- OpenGLRenderer* mCanvas = nullptr;
#if HWUI_NEW_OPS
BakedOpRenderer::LightInfo mLightInfo;
FrameBuilder::LightGeometry mLightGeometry = { {0, 0, 0}, 0 };
+#else
+ OpenGLRenderer* mCanvas = nullptr;
#endif
bool mHaveNewSurface = false;
diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp
index 04223a7..16dd108 100644
--- a/libs/hwui/renderthread/RenderProxy.cpp
+++ b/libs/hwui/renderthread/RenderProxy.cpp
@@ -56,6 +56,7 @@
enum {
FrameStats = 1 << 0,
Reset = 1 << 1,
+ JankStats = 1 << 2,
};
};
@@ -415,7 +416,6 @@
CREATE_BRIDGE4(dumpProfileInfo, CanvasContext* context, RenderThread* thread,
int fd, int dumpFlags) {
args->context->profiler().dumpData(args->fd);
- args->thread->jankTracker().dump(args->fd);
if (args->dumpFlags & DumpFlags::FrameStats) {
args->context->dumpFrames(args->fd);
}
diff --git a/libs/hwui/tests/common/TestUtils.cpp b/libs/hwui/tests/common/TestUtils.cpp
index 059e9ae..c762eed 100644
--- a/libs/hwui/tests/common/TestUtils.cpp
+++ b/libs/hwui/tests/common/TestUtils.cpp
@@ -44,6 +44,7 @@
renderthread::RenderThread& renderThread, uint32_t width, uint32_t height,
const SkMatrix& transform) {
Layer* layer = LayerRenderer::createTextureLayer(renderThread.renderState());
+ layer->getTransform().load(transform);
sp<DeferredLayerUpdater> layerUpdater = new DeferredLayerUpdater(layer);
layerUpdater->setSize(width, height);
diff --git a/libs/hwui/tests/common/TestUtils.h b/libs/hwui/tests/common/TestUtils.h
index 2d1e2e9..5492035 100644
--- a/libs/hwui/tests/common/TestUtils.h
+++ b/libs/hwui/tests/common/TestUtils.h
@@ -218,7 +218,7 @@
private:
static void syncHierarchyPropertiesAndDisplayListImpl(RenderNode* node) {
node->syncProperties();
- node->syncDisplayList();
+ node->syncDisplayList(nullptr);
auto displayList = node->getDisplayList();
if (displayList) {
for (auto&& childOp : displayList->getChildren()) {
diff --git a/libs/hwui/tests/microbench/FontBench.cpp b/libs/hwui/tests/microbench/FontBench.cpp
new file mode 100644
index 0000000..df3d041
--- /dev/null
+++ b/libs/hwui/tests/microbench/FontBench.cpp
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <benchmark/benchmark.h>
+
+#include "GammaFontRenderer.h"
+#include "tests/common/TestUtils.h"
+
+#include <SkPaint.h>
+
+using namespace android;
+using namespace android::uirenderer;
+
+void BM_FontRenderer_precache_cachehits(benchmark::State& state) {
+ TestUtils::runOnRenderThread([&state](renderthread::RenderThread& thread) {
+ SkPaint paint;
+ paint.setTextSize(20);
+ paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
+ GammaFontRenderer gammaFontRenderer;
+ FontRenderer& fontRenderer = gammaFontRenderer.getFontRenderer();
+ fontRenderer.setFont(&paint, SkMatrix::I());
+
+ std::vector<glyph_t> glyphs;
+ std::vector<float> positions;
+ float totalAdvance;
+ uirenderer::Rect bounds;
+ TestUtils::layoutTextUnscaled(paint, "This is a test",
+ &glyphs, &positions, &totalAdvance, &bounds);
+
+ fontRenderer.precache(&paint, glyphs.data(), glyphs.size(), SkMatrix::I());
+
+ while (state.KeepRunning()) {
+ fontRenderer.precache(&paint, glyphs.data(), glyphs.size(), SkMatrix::I());
+ }
+ });
+}
+BENCHMARK(BM_FontRenderer_precache_cachehits);
diff --git a/libs/hwui/tests/microbench/FrameBuilderBench.cpp b/libs/hwui/tests/microbench/FrameBuilderBench.cpp
index 9daf633..0aef620 100644
--- a/libs/hwui/tests/microbench/FrameBuilderBench.cpp
+++ b/libs/hwui/tests/microbench/FrameBuilderBench.cpp
@@ -113,15 +113,17 @@
};
void BM_FrameBuilder_defer_scene(benchmark::State& state) {
- const char* sceneName = *(SCENES.begin() + state.range_x());
- state.SetLabel(sceneName);
- auto nodes = getSyncedSceneNodes(sceneName);
- while (state.KeepRunning()) {
- FrameBuilder frameBuilder(sEmptyLayerUpdateQueue,
- SkRect::MakeWH(gDisplay.w, gDisplay.h), gDisplay.w, gDisplay.h,
- nodes, sLightGeometry, Caches::getInstance());
- benchmark::DoNotOptimize(&frameBuilder);
- }
+ TestUtils::runOnRenderThread([&state](RenderThread& thread) {
+ const char* sceneName = *(SCENES.begin() + state.range_x());
+ state.SetLabel(sceneName);
+ auto nodes = getSyncedSceneNodes(sceneName);
+ while (state.KeepRunning()) {
+ FrameBuilder frameBuilder(sEmptyLayerUpdateQueue,
+ SkRect::MakeWH(gDisplay.w, gDisplay.h), gDisplay.w, gDisplay.h,
+ nodes, sLightGeometry, Caches::getInstance());
+ benchmark::DoNotOptimize(&frameBuilder);
+ }
+ });
}
BENCHMARK(BM_FrameBuilder_defer_scene)->DenseRange(0, SCENES.size() - 1);
diff --git a/libs/hwui/tests/unit/BakedOpDispatcherTests.cpp b/libs/hwui/tests/unit/BakedOpDispatcherTests.cpp
index 654ddc6..5471486 100644
--- a/libs/hwui/tests/unit/BakedOpDispatcherTests.cpp
+++ b/libs/hwui/tests/unit/BakedOpDispatcherTests.cpp
@@ -85,7 +85,9 @@
<< "Should see conservative offset from PathCache::computeBounds";
Rect expectedBounds(10, 15, 20, 25);
expectedBounds.outset(expectedOffset);
+#if !HWUI_NEW_OPS
EXPECT_EQ(expectedBounds, glop.bounds) << "bounds outset by stroke 'offset'";
+#endif
Matrix4 expectedModelView;
expectedModelView.loadTranslate(10 - expectedOffset, 15 - expectedOffset, 0);
expectedModelView.scale(10 + 2 * expectedOffset, 10 + 2 * expectedOffset, 1);
diff --git a/libs/hwui/tests/unit/FrameBuilderTests.cpp b/libs/hwui/tests/unit/FrameBuilderTests.cpp
index dca56d4..bcf31ae 100644
--- a/libs/hwui/tests/unit/FrameBuilderTests.cpp
+++ b/libs/hwui/tests/unit/FrameBuilderTests.cpp
@@ -30,6 +30,7 @@
namespace uirenderer {
const LayerUpdateQueue sEmptyLayerUpdateQueue;
+const std::vector< sp<RenderNode> > sEmptyNodeList;
const FrameBuilder::LightGeometry sLightGeometry = { {100, 100, 100}, 50};
@@ -216,6 +217,122 @@
<< "Expect number of ops = 2 * loop count";
}
+RENDERTHREAD_TEST(FrameBuilder, empty_noFbo0) {
+ class EmptyNoFbo0TestRenderer : public TestRendererBase {
+ public:
+ void startFrame(uint32_t width, uint32_t height, const Rect& repaintRect) override {
+ ADD_FAILURE() << "Primary frame draw not expected in this test";
+ }
+ void endFrame(const Rect& repaintRect) override {
+ ADD_FAILURE() << "Primary frame draw not expected in this test";
+ }
+ };
+
+ // Pass empty node list, so no work is enqueued for Fbo0
+ FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
+ sEmptyNodeList, sLightGeometry, Caches::getInstance());
+ EmptyNoFbo0TestRenderer renderer;
+ frameBuilder.replayBakedOps<TestDispatcher>(renderer);
+}
+
+RENDERTHREAD_TEST(FrameBuilder, empty_withFbo0) {
+ class EmptyWithFbo0TestRenderer : public TestRendererBase {
+ public:
+ void startFrame(uint32_t width, uint32_t height, const Rect& repaintRect) override {
+ EXPECT_EQ(0, mIndex++);
+ }
+ void endFrame(const Rect& repaintRect) override {
+ EXPECT_EQ(1, mIndex++);
+ }
+ };
+ auto node = TestUtils::createNode(10, 10, 110, 110,
+ [](RenderProperties& props, RecordingCanvas& canvas) {
+ // no drawn content
+ });
+ auto syncedNodeList = TestUtils::createSyncedNodeList(node);
+
+ // Draw, but pass empty node list, so no work is done for primary frame
+ FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
+ syncedNodeList, sLightGeometry, Caches::getInstance());
+ EmptyWithFbo0TestRenderer renderer;
+ frameBuilder.replayBakedOps<TestDispatcher>(renderer);
+ EXPECT_EQ(2, renderer.getIndex()) << "No drawing content produced,"
+ " but fbo0 update lifecycle should still be observed";
+}
+
+RENDERTHREAD_TEST(FrameBuilder, avoidOverdraw_rects) {
+ class AvoidOverdrawRectsTestRenderer : public TestRendererBase {
+ public:
+ void onRectOp(const RectOp& op, const BakedOpState& state) override {
+ EXPECT_EQ(mIndex++, 0) << "Should be one rect";
+ EXPECT_EQ(Rect(10, 10, 190, 190), op.unmappedBounds)
+ << "Last rect should occlude others.";
+ }
+ };
+ auto node = TestUtils::createNode(0, 0, 200, 200,
+ [](RenderProperties& props, RecordingCanvas& canvas) {
+ canvas.drawRect(0, 0, 200, 200, SkPaint());
+ canvas.drawRect(0, 0, 200, 200, SkPaint());
+ canvas.drawRect(10, 10, 190, 190, SkPaint());
+ });
+
+ // Damage (and therefore clip) is same as last draw, subset of renderable area.
+ // This means last op occludes other contents, and they'll be rejected to avoid overdraw.
+ SkRect damageRect = SkRect::MakeLTRB(10, 10, 190, 190);
+ FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, damageRect, 200, 200,
+ TestUtils::createSyncedNodeList(node), sLightGeometry, Caches::getInstance());
+
+ EXPECT_EQ(3u, node->getDisplayList()->getOps().size())
+ << "Recording must not have rejected ops, in order for this test to be valid";
+
+ AvoidOverdrawRectsTestRenderer renderer;
+ frameBuilder.replayBakedOps<TestDispatcher>(renderer);
+ EXPECT_EQ(1, renderer.getIndex()) << "Expect exactly one op";
+}
+
+RENDERTHREAD_TEST(FrameBuilder, avoidOverdraw_bitmaps) {
+ static SkBitmap opaqueBitmap = TestUtils::createSkBitmap(50, 50,
+ SkColorType::kRGB_565_SkColorType);
+ static SkBitmap transpBitmap = TestUtils::createSkBitmap(50, 50,
+ SkColorType::kAlpha_8_SkColorType);
+ class AvoidOverdrawBitmapsTestRenderer : public TestRendererBase {
+ public:
+ void onBitmapOp(const BitmapOp& op, const BakedOpState& state) override {
+ switch(mIndex++) {
+ case 0:
+ EXPECT_EQ(opaqueBitmap.pixelRef(), op.bitmap->pixelRef());
+ break;
+ case 1:
+ EXPECT_EQ(transpBitmap.pixelRef(), op.bitmap->pixelRef());
+ break;
+ default:
+ ADD_FAILURE() << "Only two ops expected.";
+ }
+ }
+ };
+
+ auto node = TestUtils::createNode(0, 0, 50, 50,
+ [](RenderProperties& props, RecordingCanvas& canvas) {
+ canvas.drawRect(0, 0, 50, 50, SkPaint());
+ canvas.drawRect(0, 0, 50, 50, SkPaint());
+ canvas.drawBitmap(transpBitmap, 0, 0, nullptr);
+
+ // only the below draws should remain, since they're
+ canvas.drawBitmap(opaqueBitmap, 0, 0, nullptr);
+ canvas.drawBitmap(transpBitmap, 0, 0, nullptr);
+ });
+
+ FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(50, 50), 50, 50,
+ TestUtils::createSyncedNodeList(node), sLightGeometry, Caches::getInstance());
+
+ EXPECT_EQ(5u, node->getDisplayList()->getOps().size())
+ << "Recording must not have rejected ops, in order for this test to be valid";
+
+ AvoidOverdrawBitmapsTestRenderer renderer;
+ frameBuilder.replayBakedOps<TestDispatcher>(renderer);
+ EXPECT_EQ(2, renderer.getIndex()) << "Expect exactly two ops";
+}
+
RENDERTHREAD_TEST(FrameBuilder, clippedMerging) {
class ClippedMergingTestRenderer : public TestRendererBase {
public:
@@ -372,8 +489,8 @@
EXPECT_EQ(3, renderer.getIndex()) << "Expect 3 ops";
}
-RENDERTHREAD_TEST(FrameBuilder, textureLayer) {
- class TextureLayerTestRenderer : public TestRendererBase {
+RENDERTHREAD_TEST(FrameBuilder, textureLayer_clipLocalMatrix) {
+ class TextureLayerClipLocalMatrixTestRenderer : public TestRendererBase {
public:
void onTextureLayerOp(const TextureLayerOp& op, const BakedOpState& state) override {
EXPECT_EQ(0, mIndex++);
@@ -398,11 +515,56 @@
});
FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
TestUtils::createSyncedNodeList(node), sLightGeometry, Caches::getInstance());
- TextureLayerTestRenderer renderer;
+ TextureLayerClipLocalMatrixTestRenderer renderer;
frameBuilder.replayBakedOps<TestDispatcher>(renderer);
EXPECT_EQ(1, renderer.getIndex());
}
+RENDERTHREAD_TEST(FrameBuilder, textureLayer_combineMatrices) {
+ class TextureLayerCombineMatricesTestRenderer : public TestRendererBase {
+ public:
+ void onTextureLayerOp(const TextureLayerOp& op, const BakedOpState& state) override {
+ EXPECT_EQ(0, mIndex++);
+
+ Matrix4 expected;
+ expected.loadTranslate(35, 45, 0);
+ EXPECT_MATRIX_APPROX_EQ(expected, state.computedState.transform);
+ }
+ };
+
+ auto layerUpdater = TestUtils::createTextureLayerUpdater(renderThread, 100, 100,
+ SkMatrix::MakeTrans(5, 5));
+
+ auto node = TestUtils::createNode(0, 0, 200, 200,
+ [&layerUpdater](RenderProperties& props, RecordingCanvas& canvas) {
+ canvas.save(SaveFlags::MatrixClip);
+ canvas.translate(30, 40);
+ canvas.drawLayer(layerUpdater.get());
+ canvas.restore();
+ });
+
+ FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
+ TestUtils::createSyncedNodeList(node), sLightGeometry, Caches::getInstance());
+ TextureLayerCombineMatricesTestRenderer renderer;
+ frameBuilder.replayBakedOps<TestDispatcher>(renderer);
+ EXPECT_EQ(1, renderer.getIndex());
+}
+
+RENDERTHREAD_TEST(FrameBuilder, textureLayer_reject) {
+ auto layerUpdater = TestUtils::createTextureLayerUpdater(renderThread, 100, 100,
+ SkMatrix::MakeTrans(5, 5));
+ layerUpdater->backingLayer()->setRenderTarget(GL_NONE); // Should be rejected
+
+ auto node = TestUtils::createNode(0, 0, 200, 200,
+ [&layerUpdater](RenderProperties& props, RecordingCanvas& canvas) {
+ canvas.drawLayer(layerUpdater.get());
+ });
+ FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
+ TestUtils::createSyncedNodeList(node), sLightGeometry, Caches::getInstance());
+ FailRenderer renderer;
+ frameBuilder.replayBakedOps<TestDispatcher>(renderer);
+}
+
RENDERTHREAD_TEST(FrameBuilder, functor_reject) {
class FunctorTestRenderer : public TestRendererBase {
public:
@@ -1033,6 +1195,64 @@
*(parent->getLayerHandle()) = nullptr;
}
+
+RENDERTHREAD_TEST(FrameBuilder, buildLayer) {
+ class BuildLayerTestRenderer : public TestRendererBase {
+ public:
+ void startRepaintLayer(OffscreenBuffer* offscreenBuffer, const Rect& repaintRect) override {
+ EXPECT_EQ(0, mIndex++);
+ EXPECT_EQ(100u, offscreenBuffer->viewportWidth);
+ EXPECT_EQ(100u, offscreenBuffer->viewportHeight);
+ EXPECT_EQ(Rect(25, 25, 75, 75), repaintRect);
+ }
+ void onColorOp(const ColorOp& op, const BakedOpState& state) override {
+ EXPECT_EQ(1, mIndex++);
+
+ EXPECT_TRUE(state.computedState.transform.isIdentity())
+ << "Transform should be reset within layer";
+
+ EXPECT_EQ(Rect(25, 25, 75, 75), state.computedState.clipRect())
+ << "Damage rect should be used to clip layer content";
+ }
+ void endLayer() override {
+ EXPECT_EQ(2, mIndex++);
+ }
+ void startFrame(uint32_t width, uint32_t height, const Rect& repaintRect) override {
+ ADD_FAILURE() << "Primary frame draw not expected in this test";
+ }
+ void endFrame(const Rect& repaintRect) override {
+ ADD_FAILURE() << "Primary frame draw not expected in this test";
+ }
+ };
+
+ auto node = TestUtils::createNode(10, 10, 110, 110,
+ [](RenderProperties& props, RecordingCanvas& canvas) {
+ props.mutateLayerProperties().setType(LayerType::RenderLayer);
+ canvas.drawColor(SK_ColorWHITE, SkXfermode::Mode::kSrcOver_Mode);
+ });
+ OffscreenBuffer** layerHandle = node->getLayerHandle();
+
+ // create RenderNode's layer here in same way prepareTree would
+ OffscreenBuffer layer(renderThread.renderState(), Caches::getInstance(), 100, 100);
+ *layerHandle = &layer;
+
+ auto syncedNodeList = TestUtils::createSyncedNodeList(node);
+
+ // only enqueue partial damage
+ LayerUpdateQueue layerUpdateQueue; // Note: enqueue damage post-sync, so bounds are valid
+ layerUpdateQueue.enqueueLayerWithDamage(node.get(), Rect(25, 25, 75, 75));
+
+ // Draw, but pass empty node list, so no work is done for primary frame
+ FrameBuilder frameBuilder(layerUpdateQueue, SkRect::MakeWH(1, 1), 1, 1,
+ sEmptyNodeList, sLightGeometry, Caches::getInstance());
+ BuildLayerTestRenderer renderer;
+ frameBuilder.replayBakedOps<TestDispatcher>(renderer);
+ EXPECT_EQ(3, renderer.getIndex());
+
+ // clean up layer pointer, so we can safely destruct RenderNode
+ *layerHandle = nullptr;
+}
+
static void drawOrderedRect(RecordingCanvas* canvas, uint8_t expectedDrawOrder) {
SkPaint paint;
paint.setColor(SkColorSetARGB(256, 0, 0, expectedDrawOrder)); // order put in blue channel
diff --git a/libs/hwui/tests/unit/GlopBuilderTests.cpp b/libs/hwui/tests/unit/GlopBuilderTests.cpp
index 454011f..95543d3 100644
--- a/libs/hwui/tests/unit/GlopBuilderTests.cpp
+++ b/libs/hwui/tests/unit/GlopBuilderTests.cpp
@@ -85,7 +85,9 @@
}
static void expectGlopEq(Glop& expectedGlop, Glop& builtGlop) {
+#if !HWUI_NEW_OPS
EXPECT_EQ(expectedGlop.bounds, builtGlop.bounds);
+#endif
expectBlendEq(expectedGlop.blend, builtGlop.blend);
expectFillEq(expectedGlop.fill, builtGlop.fill);
expectMeshEq(expectedGlop.mesh, builtGlop.mesh);
@@ -136,7 +138,9 @@
// unit quad also should be translate by additional (0.3, 0.3) to snap to exact pixels.
goldenGlop->transform.modelView.loadTranslate(1.3, 1.3, 0);
goldenGlop->transform.modelView.scale(99, 99, 1);
+#if !HWUI_NEW_OPS
goldenGlop->bounds = android::uirenderer::Rect(1.70, 1.70, 100.70, 100.70);
+#endif
goldenGlop->transform.canvas = simpleTranslate;
goldenGlop->fill.texture.filter = GL_NEAREST;
expectGlopEq(*goldenGlop, glop);
diff --git a/libs/hwui/tests/unit/RecordingCanvasTests.cpp b/libs/hwui/tests/unit/RecordingCanvasTests.cpp
index 1c240db..58376c6 100644
--- a/libs/hwui/tests/unit/RecordingCanvasTests.cpp
+++ b/libs/hwui/tests/unit/RecordingCanvasTests.cpp
@@ -16,6 +16,7 @@
#include <gtest/gtest.h>
+#include <DeferredLayerUpdater.h>
#include <RecordedOp.h>
#include <RecordingCanvas.h>
#include <hwui/Paint.h>
@@ -39,6 +40,12 @@
}
}
+static void validateSingleOp(std::unique_ptr<DisplayList>& dl,
+ std::function<void(const RecordedOp& op)> opValidator) {
+ ASSERT_EQ(1u, dl->getOps().size()) << "Must be exactly one op";
+ opValidator(*(dl->getOps()[0]));
+}
+
TEST(RecordingCanvas, emptyPlayback) {
auto dl = TestUtils::createDisplayList<RecordingCanvas>(100, 200, [](RecordingCanvas& canvas) {
canvas.save(SaveFlags::MatrixClip);
@@ -284,6 +291,21 @@
ASSERT_EQ(2, count);
}
+RENDERTHREAD_TEST(RecordingCanvas, textureLayer) {
+ auto layerUpdater = TestUtils::createTextureLayerUpdater(renderThread, 100, 100,
+ SkMatrix::MakeTrans(5, 5));
+
+ auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200,
+ [&layerUpdater](RecordingCanvas& canvas) {
+ canvas.drawLayer(layerUpdater.get());
+ });
+
+ validateSingleOp(dl, [] (const RecordedOp& op) {
+ ASSERT_EQ(RecordedOpId::TextureLayerOp, op.opId);
+ ASSERT_TRUE(op.localMatrix.isIdentity()) << "Op must not apply matrix at record time.";
+ });
+}
+
TEST(RecordingCanvas, saveLayer_simple) {
auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) {
canvas.saveLayerAlpha(10, 20, 190, 180, 128, SaveFlags::ClipToLayer);
@@ -596,6 +618,15 @@
EXPECT_NE(&paint, ops[2]->paint);
}
+TEST(RecordingCanvas, refBitmap) {
+ SkBitmap bitmap = TestUtils::createSkBitmap(100, 100);
+ auto dl = TestUtils::createDisplayList<RecordingCanvas>(100, 100, [&bitmap](RecordingCanvas& canvas) {
+ canvas.drawBitmap(bitmap, 0, 0, nullptr);
+ });
+ auto& bitmaps = dl->getBitmapResources();
+ EXPECT_EQ(1u, bitmaps.size());
+}
+
TEST(RecordingCanvas, refBitmapInShader_bitmapShader) {
SkBitmap bitmap = TestUtils::createSkBitmap(100, 100);
auto dl = TestUtils::createDisplayList<RecordingCanvas>(100, 100, [&bitmap](RecordingCanvas& canvas) {
diff --git a/libs/hwui/tests/unit/RenderNodeTests.cpp b/libs/hwui/tests/unit/RenderNodeTests.cpp
new file mode 100644
index 0000000..7c57a50
--- /dev/null
+++ b/libs/hwui/tests/unit/RenderNodeTests.cpp
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gtest/gtest.h>
+
+#include "RenderNode.h"
+#include "TreeInfo.h"
+#include "tests/common/TestUtils.h"
+#include "utils/Color.h"
+
+using namespace android;
+using namespace android::uirenderer;
+
+TEST(RenderNode, hasParents) {
+ auto child = TestUtils::createNode(0, 0, 200, 400,
+ [](RenderProperties& props, TestCanvas& canvas) {
+ canvas.drawColor(Color::Red_500, SkXfermode::kSrcOver_Mode);
+ });
+ auto parent = TestUtils::createNode(0, 0, 200, 400,
+ [&child](RenderProperties& props, TestCanvas& canvas) {
+ canvas.drawRenderNode(child.get());
+ });
+
+ TestUtils::syncHierarchyPropertiesAndDisplayList(parent);
+
+ EXPECT_TRUE(child->hasParents()) << "Child node has no parent";
+ EXPECT_FALSE(parent->hasParents()) << "Root node shouldn't have any parents";
+
+ TestUtils::recordNode(*parent, [](TestCanvas& canvas) {
+ canvas.drawColor(Color::Amber_500, SkXfermode::kSrcOver_Mode);
+ });
+
+ EXPECT_TRUE(child->hasParents()) << "Child should still have a parent";
+ EXPECT_FALSE(parent->hasParents()) << "Root node shouldn't have any parents";
+
+ TestUtils::syncHierarchyPropertiesAndDisplayList(parent);
+
+ EXPECT_FALSE(child->hasParents()) << "Child should be removed";
+ EXPECT_FALSE(parent->hasParents()) << "Root node shouldn't have any parents";
+}
diff --git a/libs/hwui/tests/unit/SkiaBehaviorTests.cpp b/libs/hwui/tests/unit/SkiaBehaviorTests.cpp
index 586625b..875e260 100644
--- a/libs/hwui/tests/unit/SkiaBehaviorTests.cpp
+++ b/libs/hwui/tests/unit/SkiaBehaviorTests.cpp
@@ -41,3 +41,10 @@
EXPECT_EQ(SkShader::kRepeat_TileMode, xy[1]);
EXPECT_EQ(origBitmap.pixelRef(), bitmap.pixelRef());
}
+
+TEST(SkiaBehavior, genIds) {
+ SkBitmap bitmap = TestUtils::createSkBitmap(100, 100);
+ uint32_t genId = bitmap.getGenerationID();
+ bitmap.notifyPixelsChanged();
+ EXPECT_NE(genId, bitmap.getGenerationID());
+}
diff --git a/libs/hwui/tests/unit/SkiaCanvasTests.cpp b/libs/hwui/tests/unit/SkiaCanvasTests.cpp
new file mode 100644
index 0000000..5a01193
--- /dev/null
+++ b/libs/hwui/tests/unit/SkiaCanvasTests.cpp
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "tests/common/TestUtils.h"
+
+#include <gtest/gtest.h>
+#include <RecordingCanvas.h>
+#include <SkPicture.h>
+#include <SkPictureRecorder.h>
+
+using namespace android;
+using namespace android::uirenderer;
+
+/**
+ * Verify that we get the same culling bounds for text for (1) drawing glyphs
+ * directly to a Canvas or (2) going through a SkPicture as an intermediate step.
+ */
+TEST(SkiaCanvasProxy, drawGlyphsViaPicture) {
+ auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) {
+ // setup test variables
+ SkPaint paint;
+ paint.setAntiAlias(true);
+ paint.setTextSize(20);
+ paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
+ static const char* text = "testing text bounds";
+
+ // draw text directly into Recording canvas
+ TestUtils::drawUtf8ToCanvas(&canvas, text, paint, 25, 25);
+
+ // record the same text draw into a SkPicture and replay it into a Recording canvas
+ SkPictureRecorder recorder;
+ SkCanvas* skCanvas = recorder.beginRecording(200, 200, NULL, 0);
+ std::unique_ptr<Canvas> pictCanvas(Canvas::create_canvas(skCanvas));
+ TestUtils::drawUtf8ToCanvas(pictCanvas.get(), text, paint, 25, 25);
+ SkAutoTUnref<const SkPicture> picture(recorder.endRecording());
+
+ canvas.asSkCanvas()->drawPicture(picture);
+ });
+
+ // verify that the text bounds and matrices match
+ ASSERT_EQ(2U, dl->getOps().size());
+ auto directOp = dl->getOps()[0];
+ auto pictureOp = dl->getOps()[1];
+ ASSERT_EQ(RecordedOpId::TextOp, directOp->opId);
+ EXPECT_EQ(directOp->opId, pictureOp->opId);
+ EXPECT_EQ(directOp->unmappedBounds, pictureOp->unmappedBounds);
+ EXPECT_EQ(directOp->localMatrix, pictureOp->localMatrix);
+}
diff --git a/libs/hwui/utils/PaintUtils.h b/libs/hwui/utils/PaintUtils.h
index db53713..4faab9a 100644
--- a/libs/hwui/utils/PaintUtils.h
+++ b/libs/hwui/utils/PaintUtils.h
@@ -67,6 +67,21 @@
&& getXfermode(paint.getXfermode()) == SkXfermode::kSrcOver_Mode;
}
+ static bool isOpaquePaint(const SkPaint* paint) {
+ if (!paint) return true; // default (paintless) behavior is SrcOver, black
+
+ if (paint->getAlpha() != 0xFF
+ || PaintUtils::isBlendedShader(paint->getShader())
+ || PaintUtils::isBlendedColorFilter(paint->getColorFilter())) {
+ return false;
+ }
+
+ // Only let simple srcOver / src blending modes declare opaque, since behavior is clear.
+ SkXfermode::Mode mode = getXfermode(paint->getXfermode());
+ return mode == SkXfermode::Mode::kSrcOver_Mode
+ || mode == SkXfermode::Mode::kSrc_Mode;
+ }
+
static bool isBlendedShader(const SkShader* shader) {
if (shader == nullptr) {
return false;
diff --git a/location/java/android/location/GnssMeasurement.java b/location/java/android/location/GnssMeasurement.java
index 17ce533..d78ccee 100644
--- a/location/java/android/location/GnssMeasurement.java
+++ b/location/java/android/location/GnssMeasurement.java
@@ -81,41 +81,42 @@
*/
public static final int MULTIPATH_INDICATOR_NOT_USED = 2;
- /**
- * The state of GNSS receiver the measurement is invalid or unknown.
- */
+ /** This GNSS measurement's tracking state is invalid or unknown. */
public static final int STATE_UNKNOWN = 0;
-
- /**
- * The state of the GNSS receiver is ranging code lock.
- */
+ /** This GNSS measurement's tracking state has code lock. */
public static final int STATE_CODE_LOCK = (1<<0);
-
- /**
- * The state of the GNSS receiver is in bit sync.
- */
+ /** This GNSS measurement's tracking state has bit sync. */
public static final int STATE_BIT_SYNC = (1<<1);
-
- /**
- *The state of the GNSS receiver is in sub-frame sync.
- */
+ /** This GNSS measurement's tracking state has sub-frame sync. */
public static final int STATE_SUBFRAME_SYNC = (1<<2);
-
- /**
- * The state of the GNSS receiver has TOW decoded.
- */
+ /** This GNSS measurement's tracking state has time-of-week decoded. */
public static final int STATE_TOW_DECODED = (1<<3);
-
- /**
- * The state of the GNSS receiver contains millisecond ambiguity.
- */
+ /** This GNSS measurement's tracking state contains millisecond ambiguity. */
public static final int STATE_MSEC_AMBIGUOUS = (1<<4);
+ /** This GNSS measurement's tracking state has symbol sync. */
+ public static final int STATE_SYMBOL_SYNC = (1<<5);
+ /** This Glonass measurement's tracking state has string sync. */
+ public static final int STATE_GLO_STRING_SYNC = (1<<6);
+ /** This Glonass measurement's tracking state has time-of-day decoded. */
+ public static final int STATE_GLO_TOD_DECODED = (1<<7);
+ /** This Beidou measurement's tracking state has D2 bit sync. */
+ public static final int STATE_BDS_D2_BIT_SYNC = (1<<8);
+ /** This Beidou measurement's tracking state has D2 sub-frame sync. */
+ public static final int STATE_BDS_D2_SUBFRAME_SYNC = (1<<9);
+ /** This Galileo measurement's tracking state has E1B/C code lock. */
+ public static final int STATE_GAL_E1BC_CODE_LOCK = (1<<10);
+ /** This Galileo measurement's tracking state has E1C secondary code lock. */
+ public static final int STATE_GAL_E1C_2ND_CODE_LOCK = (1<<11);
+ /** This Galileo measurement's tracking state has E1B page sync. */
+ public static final int STATE_GAL_E1B_PAGE_SYNC = (1<<12);
+ /** This SBAS measurement's tracking state has whole second level sync. */
+ public static final int STATE_SBAS_SYNC = (1<<13);
/**
- * All the GNSS receiver state flags.
+ * All the GNSS receiver state flags, for bit masking purposes (not a sensible state for any
+ * individual measurement.)
*/
- private static final int STATE_ALL = STATE_CODE_LOCK | STATE_BIT_SYNC | STATE_SUBFRAME_SYNC
- | STATE_TOW_DECODED | STATE_MSEC_AMBIGUOUS;
+ private static final int STATE_ALL = 0x3fff; // 2 bits + 4 bits + 4 bits + 4 bits = 14 bits
/**
* The state of the 'Accumulated Delta Range' is invalid or unknown.
@@ -276,29 +277,58 @@
if (mState == STATE_UNKNOWN) {
return "Unknown";
}
+
StringBuilder builder = new StringBuilder();
- if ((mState & STATE_CODE_LOCK) == STATE_CODE_LOCK) {
+ if ((mState & STATE_CODE_LOCK) != 0) {
builder.append("CodeLock|");
}
- if ((mState & STATE_BIT_SYNC) == STATE_BIT_SYNC) {
+ if ((mState & STATE_BIT_SYNC) != 0) {
builder.append("BitSync|");
}
- if ((mState & STATE_SUBFRAME_SYNC) == STATE_SUBFRAME_SYNC) {
+ if ((mState & STATE_SUBFRAME_SYNC) != 0) {
builder.append("SubframeSync|");
}
- if ((mState & STATE_TOW_DECODED) == STATE_TOW_DECODED) {
+ if ((mState & STATE_TOW_DECODED) != 0) {
builder.append("TowDecoded|");
}
- if ((mState & STATE_MSEC_AMBIGUOUS) == STATE_MSEC_AMBIGUOUS) {
- builder.append("MsecAmbiguous");
+ if ((mState & STATE_MSEC_AMBIGUOUS) != 0) {
+ builder.append("MsecAmbiguous|");
}
+ if ((mState & STATE_SYMBOL_SYNC) != 0) {
+ builder.append("SymbolSync|");
+ }
+ if ((mState & STATE_GLO_STRING_SYNC) != 0) {
+ builder.append("GloStringSync|");
+ }
+ if ((mState & STATE_GLO_TOD_DECODED) != 0) {
+ builder.append("GloTodDecoded|");
+ }
+ if ((mState & STATE_BDS_D2_BIT_SYNC) != 0) {
+ builder.append("BdsD2BitSync|");
+ }
+ if ((mState & STATE_BDS_D2_SUBFRAME_SYNC) != 0) {
+ builder.append("BdsD2SubframeSync|");
+ }
+ if ((mState & STATE_GAL_E1BC_CODE_LOCK) != 0) {
+ builder.append("GalE1bcCodeLock|");
+ }
+ if ((mState & STATE_GAL_E1C_2ND_CODE_LOCK) != 0) {
+ builder.append("E1c2ndCodeLock|");
+ }
+ if ((mState & STATE_GAL_E1B_PAGE_SYNC) != 0) {
+ builder.append("GalE1bPageSync|");
+ }
+ if ((mState & STATE_SBAS_SYNC) != 0) {
+ builder.append("SbasSync|");
+ }
+
int remainingStates = mState & ~STATE_ALL;
if (remainingStates > 0) {
builder.append("Other(");
builder.append(Integer.toBinaryString(remainingStates));
builder.append(")|");
}
- builder.deleteCharAt(builder.length() - 1);
+ builder.setLength(builder.length() - 1);
return builder.toString();
}
diff --git a/location/java/android/location/GnssStatus.java b/location/java/android/location/GnssStatus.java
index 9c509d6..d76feec 100644
--- a/location/java/android/location/GnssStatus.java
+++ b/location/java/android/location/GnssStatus.java
@@ -121,7 +121,7 @@
* @param satIndex the index of the satellite in the list.
*/
public float getElevationDegrees(int satIndex) {
- return 0f;
+ return mElevations[satIndex];
}
/**
diff --git a/location/java/android/location/INetInitiatedListener.aidl b/location/java/android/location/INetInitiatedListener.aidl
index f2f5a32..fc64dd6 100644
--- a/location/java/android/location/INetInitiatedListener.aidl
+++ b/location/java/android/location/INetInitiatedListener.aidl
@@ -1,26 +1,26 @@
-/*
-**
-** Copyright 2008, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
-
-package android.location;
-
-/**
- * {@hide}
- */
-interface INetInitiatedListener
-{
- boolean sendNiResponse(int notifId, int userResponse);
-}
+/*
+**
+** Copyright 2008, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+package android.location;
+
+/**
+ * {@hide}
+ */
+interface INetInitiatedListener
+{
+ boolean sendNiResponse(int notifId, int userResponse);
+}
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index 3c42161..00eff91 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -2149,7 +2149,7 @@
}
if (listener != null) {
Log.d(TAG, "AudioManager dispatching onAudioFocusChange("
- + msg.what + ") for " + msg.obj);
+ + msg.arg1 + ") for " + msg.obj);
listener.onAudioFocusChange(msg.arg1);
}
break;
@@ -2157,7 +2157,7 @@
final RecordConfigChangeCallbackData cbData =
(RecordConfigChangeCallbackData) msg.obj;
if (cbData.mCb != null) {
- cbData.mCb.onRecordConfigChanged(cbData.mConfigs);
+ cbData.mCb.onRecordingConfigChanged(cbData.mConfigs);
}
break;
default:
@@ -2746,7 +2746,7 @@
* @param configs array containing the results of
* {@link AudioManager#getActiveRecordingConfigurations()}.
*/
- public void onRecordConfigChanged(AudioRecordingConfiguration[] configs) {}
+ public void onRecordingConfigChanged(AudioRecordingConfiguration[] configs) {}
}
private static class AudioRecordingCallbackInfo {
diff --git a/media/java/android/media/AudioTrack.java b/media/java/android/media/AudioTrack.java
index d9caf03..621129d 100644
--- a/media/java/android/media/AudioTrack.java
+++ b/media/java/android/media/AudioTrack.java
@@ -596,14 +596,14 @@
* AudioTrack player = new AudioTrack.Builder()
* .setAudioAttributes(new AudioAttributes.Builder()
* .setUsage(AudioAttributes.USAGE_ALARM)
- * .setContentType(CONTENT_TYPE_MUSIC)
+ * .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
* .build())
* .setAudioFormat(new AudioFormat.Builder()
* .setEncoding(AudioFormat.ENCODING_PCM_16BIT)
- * .setSampleRate(441000)
+ * .setSampleRate(44100)
* .setChannelMask(AudioFormat.CHANNEL_OUT_STEREO)
* .build())
- * .setBufferSize(minBuffSize)
+ * .setBufferSizeInBytes(minBuffSize)
* .build();
* </pre>
* <p>
@@ -1120,7 +1120,7 @@
* <p> See also {@link AudioManager#getProperty(String)} for key
* {@link AudioManager#PROPERTY_OUTPUT_FRAMES_PER_BUFFER}.
* @return current size in frames of the <code>AudioTrack</code> buffer.
- * @throws IllegalStateException
+ * @throws IllegalStateException if track is not initialized.
*/
public int getBufferSizeInFrames() {
return native_get_buffer_size_frames();
@@ -1147,7 +1147,7 @@
* @param bufferSizeInFrames requested buffer size
* @return the actual buffer size in frames or an error code,
* {@link #ERROR_BAD_VALUE}, {@link #ERROR_INVALID_OPERATION}
- * @throws IllegalStateException
+ * @throws IllegalStateException if track is not initialized.
*/
public int setBufferSizeInFrames(int bufferSizeInFrames) {
if (mDataLoadMode == MODE_STATIC || mState == STATE_UNINITIALIZED) {
@@ -1176,7 +1176,7 @@
* <p> See also {@link AudioManager#getProperty(String)} for key
* {@link AudioManager#PROPERTY_OUTPUT_FRAMES_PER_BUFFER}.
* @return maximum size in frames of the <code>AudioTrack</code> buffer.
- * @throws IllegalStateException
+ * @throws IllegalStateException if track is not initialized.
*/
public int getBufferCapacityInFrames() {
return native_get_buffer_capacity_frames();
diff --git a/media/java/android/media/ExifInterface.java b/media/java/android/media/ExifInterface.java
index 4bf0852..3d7e744 100644
--- a/media/java/android/media/ExifInterface.java
+++ b/media/java/android/media/ExifInterface.java
@@ -161,9 +161,14 @@
public static final String TAG_EXPOSURE_PROGRAM = "ExposureProgram";
/** Type is double. */
public static final String TAG_EXPOSURE_TIME = "ExposureTime";
- /** Type is String. */
+ /** Type is double. */
public static final String TAG_F_NUMBER = "FNumber";
- /** Type is String. */
+ /**
+ * Type is double.
+ *
+ * @deprecated use {@link #TAG_F_NUMBER} instead
+ */
+ @Deprecated
public static final String TAG_APERTURE = "FNumber";
/** Type is String. */
public static final String TAG_FILE_SOURCE = "FileSource";
@@ -185,9 +190,14 @@
public static final String TAG_FOCAL_PLANE_Y_RESOLUTION = "FocalPlaneYResolution";
/** Type is rational. */
public static final String TAG_GAIN_CONTROL = "GainControl";
- /** Type is String. */
+ /** Type is int. */
public static final String TAG_ISO_SPEED_RATINGS = "ISOSpeedRatings";
- /** Type is String. */
+ /**
+ * Type is int.
+ *
+ * @deprecated use {@link #TAG_ISO_SPEED_RATINGS} instead
+ */
+ @Deprecated
public static final String TAG_ISO = "ISOSpeedRatings";
/** Type is String. */
public static final String TAG_IMAGE_UNIQUE_ID = "ImageUniqueID";
@@ -225,8 +235,6 @@
public static final String TAG_SPECTRAL_SENSITIVITY = "SpectralSensitivity";
/** Type is int. */
public static final String TAG_SUBSEC_TIME = "SubSecTime";
- /** Type is int. @hide */
- public static final String TAG_SUBSECTIME = "SubSecTime";
/** Type is int. */
public static final String TAG_SUBSEC_TIME_DIGITIZED = "SubSecTimeDigitized";
/** Type is int. */
@@ -437,7 +445,7 @@
new ExifTag(TAG_F_NUMBER, 33437),
new ExifTag(TAG_EXPOSURE_PROGRAM, 34850),
new ExifTag(TAG_SPECTRAL_SENSITIVITY, 34852),
- new ExifTag(TAG_ISO, 34855),
+ new ExifTag(TAG_ISO_SPEED_RATINGS, 34855),
new ExifTag(TAG_OECF, 34856),
new ExifTag(TAG_EXIF_VERSION, 36864),
new ExifTag(TAG_DATETIME_ORIGINAL, 36867),
@@ -693,7 +701,7 @@
*/
public ExifInterface(FileDescriptor fileDescriptor) throws IOException {
if (fileDescriptor == null) {
- throw new IllegalArgumentException("parcelFileDescriptor cannot be null");
+ throw new IllegalArgumentException("fileDescriptor cannot be null");
}
mAssetInputStream = null;
mFilename = null;
@@ -705,7 +713,7 @@
try {
fileDescriptor = Os.dup(fileDescriptor);
} catch (ErrnoException e) {
- e.rethrowAsIOException();
+ throw e.rethrowAsIOException();
}
} else {
mSeekableFileDescriptor = null;
@@ -811,6 +819,9 @@
*/
public void setAttribute(String tag, String value) {
for (int i = 0 ; i < EXIF_TAGS.length; ++i) {
+ if (i == IFD_THUMBNAIL_HINT && !mHasThumbnail) {
+ continue;
+ }
if (sExifTagMapsForWriting[i].containsKey(tag)) {
mAttributes[i].put(tag, value);
}
@@ -818,6 +829,35 @@
}
/**
+ * Update the values of the tags in the tag groups if any value for the tag already was stored.
+ *
+ * @param tag the name of the tag.
+ * @param value the value of the tag.
+ * @return Returns {@code true} if updating is placed.
+ */
+ private boolean updateAttribute(String tag, String value) {
+ boolean updated = false;
+ for (int i = 0 ; i < EXIF_TAGS.length; ++i) {
+ if (mAttributes[i].containsKey(tag)) {
+ mAttributes[i].put(tag, value);
+ updated = true;
+ }
+ }
+ return updated;
+ }
+
+ /**
+ * Remove any values of the specified tag.
+ *
+ * @param tag the name of the tag.
+ */
+ private void removeAttribute(String tag) {
+ for (int i = 0 ; i < EXIF_TAGS.length; ++i) {
+ mAttributes[i].remove(tag);
+ }
+ }
+
+ /**
* This function decides which parser to read the image data according to the given input stream
* type and the content of the input stream. In each case, it reads the first three bytes to
* determine whether the image data format is JPEG or not.
@@ -853,7 +893,7 @@
} catch (IOException e) {
// Ignore exceptions in order to keep the compatibility with the old versions of
// ExifInterface.
- Log.w(TAG, "Invalid JPEG: ExifInterface got an unsupported image format file"
+ Log.w(TAG, "Invalid image: ExifInterface got an unsupported image format file"
+ "(ExifInterface supports JPEG and some RAW image formats only) "
+ "or a corrupted JPEG file to ExifInterface.", e);
} finally {
@@ -882,27 +922,22 @@
// Mark for disabling the save feature.
mIsRaw = true;
- for (Map.Entry entry : (Set<Map.Entry>) map.entrySet()) {
- String attrName = (String) entry.getKey();
-
- switch (attrName) {
- case TAG_HAS_THUMBNAIL:
- mHasThumbnail = ((String) entry.getValue()).equalsIgnoreCase("true");
- break;
- case TAG_THUMBNAIL_OFFSET:
- mThumbnailOffset = Integer.parseInt((String) entry.getValue());
- break;
- case TAG_THUMBNAIL_LENGTH:
- mThumbnailLength = Integer.parseInt((String) entry.getValue());
- break;
- case TAG_THUMBNAIL_DATA:
- mThumbnailBytes = (byte[]) entry.getValue();
- break;
- default:
- setAttribute(attrName, (String) entry.getValue());
- break;
- }
+ String value = (String) map.remove(TAG_HAS_THUMBNAIL);
+ mHasThumbnail = value != null && value.equalsIgnoreCase("true");
+ value = (String) map.remove(TAG_THUMBNAIL_OFFSET);
+ if (value != null) {
+ mThumbnailOffset = Integer.parseInt(value);
}
+ value = (String) map.remove(TAG_THUMBNAIL_LENGTH);
+ if (value != null) {
+ mThumbnailLength = Integer.parseInt(value);
+ }
+ mThumbnailBytes = (byte[]) map.remove(TAG_THUMBNAIL_DATA);
+
+ for (Map.Entry entry : (Set<Map.Entry>) map.entrySet()) {
+ setAttribute((String) entry.getKey(), (String) entry.getValue());
+ }
+
return true;
}
@@ -928,7 +963,7 @@
/**
* Save the tag data into the original image file. This is expensive because it involves
* copying all the data from one file to another and deleting the old file and renaming the
- * other. It's best to use{@link #setAttribute(String,String)} to set all attributes to write
+ * other. It's best to use {@link #setAttribute(String,String)} to set all attributes to write
* and make a single call rather than multiple calls for each attribute.
*/
public void saveAttributes() throws IOException {
@@ -963,7 +998,7 @@
Streams.copy(in, out);
}
} catch (ErrnoException e) {
- e.rethrowAsIOException();
+ throw e.rethrowAsIOException();
} finally {
IoUtils.closeQuietly(in);
IoUtils.closeQuietly(out);
@@ -982,7 +1017,7 @@
}
saveJpegAttributes(in, out);
} catch (ErrnoException e) {
- e.rethrowAsIOException();
+ throw e.rethrowAsIOException();
} finally {
IoUtils.closeQuietly(in);
IoUtils.closeQuietly(out);
@@ -1052,12 +1087,16 @@
*
* @return two-element array, the offset in the first value, and length in
* the second, or {@code null} if no thumbnail was found.
- * @hide
*/
public long[] getThumbnailRange() {
+ if (!mHasThumbnail) {
+ return null;
+ }
+
long[] range = new long[2];
range[0] = mThumbnailOffset;
range[1] = mThumbnailLength;
+
return range;
}
@@ -1120,7 +1159,7 @@
if (datetime == null) return -1;
long msecs = datetime.getTime();
- String subSecs = getAttribute(TAG_SUBSECTIME);
+ String subSecs = getAttribute(TAG_SUBSEC_TIME);
if (subSecs != null) {
try {
long sub = Long.valueOf(subSecs);
@@ -1276,7 +1315,8 @@
throw new IOException("Invalid exif");
}
length = 0;
- setAttribute("UserComment", new String(bytes, Charset.forName("US-ASCII")));
+ mAttributes[IFD_EXIF_HINT].put(TAG_USER_COMMENT,
+ new String(bytes, Charset.forName("US-ASCII")));
break;
}
@@ -1296,9 +1336,10 @@
if (dataInputStream.skipBytes(1) != 1) {
throw new IOException("Invalid SOFx");
}
- setAttribute("ImageLength",
+ mAttributes[IFD_TIFF_HINT].put(TAG_IMAGE_LENGTH,
String.valueOf(dataInputStream.readUnsignedShort()));
- setAttribute("ImageWidth", String.valueOf(dataInputStream.readUnsignedShort()));
+ mAttributes[IFD_TIFF_HINT].put(TAG_IMAGE_WIDTH,
+ String.valueOf(dataInputStream.readUnsignedShort()));
length -= 5;
break;
}
@@ -1510,7 +1551,7 @@
convertToDouble(TAG_EXPOSURE_TIME);
convertToDouble(TAG_F_NUMBER);
convertToDouble(TAG_SUBJECT_DISTANCE);
- convertToInt(TAG_ISO);
+ convertToInt(TAG_ISO_SPEED_RATINGS);
convertToDouble(TAG_EXPOSURE_BIAS_VALUE);
convertToInt(TAG_WHITE_BALANCE);
convertToInt(TAG_LIGHT_SOURCE);
@@ -1521,31 +1562,31 @@
convertToInt(TAG_GPS_ALTITUDE_REF);
convertToRational(TAG_GPS_LONGITUDE);
convertToRational(TAG_GPS_LATITUDE);
- convertToTimetamp(TAG_GPS_TIMESTAMP);
+ convertToTimestamp(TAG_GPS_TIMESTAMP);
// The value of DATETIME tag has the same value of DATETIME_ORIGINAL tag.
- String valueOfDateTimeOriginal = getAttribute("DateTimeOriginal");
+ String valueOfDateTimeOriginal = getAttribute(TAG_DATETIME_ORIGINAL);
if (valueOfDateTimeOriginal != null) {
- setAttribute(TAG_DATETIME, valueOfDateTimeOriginal);
+ mAttributes[IFD_TIFF_HINT].put(TAG_DATETIME, valueOfDateTimeOriginal);
}
// Add the default value.
if (getAttribute(TAG_IMAGE_WIDTH) == null) {
- setAttribute(TAG_IMAGE_WIDTH, "0");
+ mAttributes[IFD_TIFF_HINT].put(TAG_IMAGE_WIDTH, "0");
}
if (getAttribute(TAG_IMAGE_LENGTH) == null) {
- setAttribute(TAG_IMAGE_LENGTH, "0");
+ mAttributes[IFD_TIFF_HINT].put(TAG_IMAGE_LENGTH, "0");
}
if (getAttribute(TAG_ORIENTATION) == null) {
- setAttribute(TAG_ORIENTATION, "0");
+ mAttributes[IFD_TIFF_HINT].put(TAG_ORIENTATION, "0");
}
if (getAttribute(TAG_LIGHT_SOURCE) == null) {
- setAttribute(TAG_LIGHT_SOURCE, "0");
+ mAttributes[IFD_EXIF_HINT].put(TAG_LIGHT_SOURCE, "0");
}
}
// Converts the tag value to timestamp; Otherwise deletes the given tag.
- private void convertToTimetamp(String tagName) {
+ private void convertToTimestamp(String tagName) {
String entryValue = getAttribute(tagName);
if (entryValue == null) return;
int dataFormat = getDataFormatOfExifEntryValue(entryValue);
@@ -1566,9 +1607,9 @@
int value = numerator / denominator;
stringBuilder.append(String.format("%02d", value));
}
- setAttribute(tagName, stringBuilder.toString());
+ updateAttribute(tagName, stringBuilder.toString());
} else if (dataFormat != IFD_FORMAT_STRING) {
- setAttribute(tagName, null);
+ removeAttribute(tagName);
}
}
@@ -1595,14 +1636,14 @@
}
stringBuilder.append((double) numerator / denominator);
}
- setAttribute(tagName, stringBuilder.toString());
+ updateAttribute(tagName, stringBuilder.toString());
break;
}
case IFD_FORMAT_DOUBLE:
// Keep it as is.
break;
default:
- setAttribute(tagName, null);
+ removeAttribute(tagName);
break;
}
}
@@ -1624,14 +1665,14 @@
double doubleValue = Double.parseDouble(component);
stringBuilder.append((int) (doubleValue * 10000.0)).append("/").append(10000);
}
- setAttribute(tagName, stringBuilder.toString());
+ updateAttribute(tagName, stringBuilder.toString());
break;
}
case IFD_FORMAT_SRATIONAL:
// Keep it as is.
break;
default:
- setAttribute(tagName, null);
+ removeAttribute(tagName);
break;
}
}
@@ -1642,7 +1683,7 @@
if (entryValue == null) return;
int dataFormat = getDataFormatOfExifEntryValue(entryValue);
if (dataFormat != IFD_FORMAT_SLONG) {
- setAttribute(tagName, null);
+ removeAttribute(tagName);
}
}
@@ -1758,7 +1799,7 @@
String entryValue = readExifEntryValue(
dataInputStream, dataFormat, numberOfComponents);
if (entryValue != null) {
- setAttribute(tagName, entryValue);
+ mAttributes[hint].put(tagName, entryValue);
}
} else {
StringBuilder entryValueBuilder = new StringBuilder();
@@ -1769,7 +1810,7 @@
entryValueBuilder.append(readExifEntryValue(
dataInputStream, dataFormat, numberOfComponents));
}
- setAttribute(tagName, entryValueBuilder.toString());
+ mAttributes[hint].put(tagName, entryValueBuilder.toString());
}
if (dataInputStream.peek() != nextEntryOffset) {
@@ -1886,11 +1927,11 @@
// Remove IFD pointer tags (we'll re-add it later.)
for (ExifTag tag : IFD_POINTER_TAGS) {
- setAttribute(tag.name, null);
+ removeAttribute(tag.name);
}
// Remove old thumbnail data
- setAttribute(JPEG_INTERCHANGE_FORMAT_TAG.name, null);
- setAttribute(JPEG_INTERCHANGE_FORMAT_LENGTH_TAG.name, null);
+ removeAttribute(JPEG_INTERCHANGE_FORMAT_TAG.name);
+ removeAttribute(JPEG_INTERCHANGE_FORMAT_LENGTH_TAG.name);
// Remove null value tags.
for (int hint = 0; hint < EXIF_TAGS.length; ++hint) {
diff --git a/media/java/android/media/MediaActionSound.java b/media/java/android/media/MediaActionSound.java
index 1fee587..983ca75 100644
--- a/media/java/android/media/MediaActionSound.java
+++ b/media/java/android/media/MediaActionSound.java
@@ -45,8 +45,7 @@
private static final int NUM_MEDIA_SOUND_STREAMS = 1;
private SoundPool mSoundPool;
- private int[] mSoundIds;
- private int mSoundIdToPlay;
+ private SoundState[] mSounds;
private static final String[] SOUND_FILES = {
"/system/media/audio/ui/camera_click.ogg",
@@ -88,22 +87,57 @@
*/
public static final int STOP_VIDEO_RECORDING = 3;
- private static final int SOUND_NOT_LOADED = -1;
+ /**
+ * States for SoundState.
+ * STATE_NOT_LOADED : sample not loaded
+ * STATE_LOADING : sample being loaded: waiting for load completion callback
+ * STATE_LOADING_PLAY_REQUESTED : sample being loaded and playback request received
+ * STATE_LOADED : sample loaded, ready for playback
+ */
+ private static final int STATE_NOT_LOADED = 0;
+ private static final int STATE_LOADING = 1;
+ private static final int STATE_LOADING_PLAY_REQUESTED = 2;
+ private static final int STATE_LOADED = 3;
+ private class SoundState {
+ public final int name;
+ public int id;
+ public int state;
+
+ public SoundState(int name) {
+ this.name = name;
+ id = 0; // 0 is an invalid sample ID.
+ state = STATE_NOT_LOADED;
+ }
+ }
/**
* Construct a new MediaActionSound instance. Only a single instance is
* needed for playing any platform media action sound; you do not need a
* separate instance for each sound type.
*/
public MediaActionSound() {
- mSoundPool = new SoundPool(NUM_MEDIA_SOUND_STREAMS,
- AudioManager.STREAM_SYSTEM_ENFORCED, 0);
+ mSoundPool = new SoundPool.Builder()
+ .setMaxStreams(NUM_MEDIA_SOUND_STREAMS)
+ .setAudioAttributes(new AudioAttributes.Builder()
+ .setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION)
+ .setFlags(AudioAttributes.FLAG_AUDIBILITY_ENFORCED)
+ .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
+ .build())
+ .build();
mSoundPool.setOnLoadCompleteListener(mLoadCompleteListener);
- mSoundIds = new int[SOUND_FILES.length];
- for (int i = 0; i < mSoundIds.length; i++) {
- mSoundIds[i] = SOUND_NOT_LOADED;
+ mSounds = new SoundState[SOUND_FILES.length];
+ for (int i = 0; i < mSounds.length; i++) {
+ mSounds[i] = new SoundState(i);
}
- mSoundIdToPlay = SOUND_NOT_LOADED;
+ }
+
+ private int loadSound(SoundState sound) {
+ int id = mSoundPool.load(SOUND_FILES[sound.name], 1);
+ if (id > 0) {
+ sound.state = STATE_LOADING;
+ sound.id = id;
+ }
+ return id;
}
/**
@@ -118,13 +152,22 @@
* @see #START_VIDEO_RECORDING
* @see #STOP_VIDEO_RECORDING
*/
- public synchronized void load(int soundName) {
+ public void load(int soundName) {
if (soundName < 0 || soundName >= SOUND_FILES.length) {
throw new RuntimeException("Unknown sound requested: " + soundName);
}
- if (mSoundIds[soundName] == SOUND_NOT_LOADED) {
- mSoundIds[soundName] =
- mSoundPool.load(SOUND_FILES[soundName], 1);
+ SoundState sound = mSounds[soundName];
+ synchronized (sound) {
+ switch (sound.state) {
+ case STATE_NOT_LOADED:
+ if (loadSound(sound) <= 0) {
+ Log.e(TAG, "load() error loading sound: " + soundName);
+ }
+ break;
+ default:
+ Log.e(TAG, "load() called in wrong state: " + sound + " for sound: "+ soundName);
+ break;
+ }
}
}
@@ -159,16 +202,31 @@
* @see #START_VIDEO_RECORDING
* @see #STOP_VIDEO_RECORDING
*/
- public synchronized void play(int soundName) {
+ public void play(int soundName) {
if (soundName < 0 || soundName >= SOUND_FILES.length) {
throw new RuntimeException("Unknown sound requested: " + soundName);
}
- if (mSoundIds[soundName] == SOUND_NOT_LOADED) {
- mSoundIdToPlay =
- mSoundPool.load(SOUND_FILES[soundName], 1);
- mSoundIds[soundName] = mSoundIdToPlay;
- } else {
- mSoundPool.play(mSoundIds[soundName], 1.0f, 1.0f, 0, 0, 1.0f);
+ SoundState sound = mSounds[soundName];
+ synchronized (sound) {
+ switch (sound.state) {
+ case STATE_NOT_LOADED:
+ loadSound(sound);
+ if (loadSound(sound) <= 0) {
+ Log.e(TAG, "play() error loading sound: " + soundName);
+ break;
+ }
+ // FALL THROUGH
+
+ case STATE_LOADING:
+ sound.state = STATE_LOADING_PLAY_REQUESTED;
+ break;
+ case STATE_LOADED:
+ mSoundPool.play(sound.id, 1.0f, 1.0f, 0, 0, 1.0f);
+ break;
+ default:
+ Log.e(TAG, "play() called in wrong state: " + sound.state + " for sound: "+ soundName);
+ break;
+ }
}
}
@@ -176,14 +234,37 @@
new SoundPool.OnLoadCompleteListener() {
public void onLoadComplete(SoundPool soundPool,
int sampleId, int status) {
- if (status == 0) {
- if (mSoundIdToPlay == sampleId) {
- soundPool.play(sampleId, 1.0f, 1.0f, 0, 0, 1.0f);
- mSoundIdToPlay = SOUND_NOT_LOADED;
+ for (SoundState sound : mSounds) {
+ if (sound.id != sampleId) {
+ continue;
}
- } else {
- Log.e(TAG, "Unable to load sound for playback (status: " +
- status + ")");
+ int playSoundId = 0;
+ synchronized (sound) {
+ if (status != 0) {
+ sound.state = STATE_NOT_LOADED;
+ sound.id = 0;
+ Log.e(TAG, "OnLoadCompleteListener() error: " + status +
+ " loading sound: "+ sound.name);
+ return;
+ }
+ switch (sound.state) {
+ case STATE_LOADING:
+ sound.state = STATE_LOADED;
+ break;
+ case STATE_LOADING_PLAY_REQUESTED:
+ playSoundId = sound.id;
+ sound.state = STATE_LOADED;
+ break;
+ default:
+ Log.e(TAG, "OnLoadCompleteListener() called in wrong state: "
+ + sound.state + " for sound: "+ sound.name);
+ break;
+ }
+ }
+ if (playSoundId != 0) {
+ soundPool.play(playSoundId, 1.0f, 1.0f, 0, 0, 1.0f);
+ }
+ break;
}
}
};
@@ -195,6 +276,12 @@
*/
public void release() {
if (mSoundPool != null) {
+ for (SoundState sound : mSounds) {
+ synchronized (sound) {
+ sound.state = STATE_NOT_LOADED;
+ sound.id = 0;
+ }
+ }
mSoundPool.release();
mSoundPool = null;
}
diff --git a/media/java/android/media/MediaCodecInfo.java b/media/java/android/media/MediaCodecInfo.java
index b1c1b79..2bd9781 100644
--- a/media/java/android/media/MediaCodecInfo.java
+++ b/media/java/android/media/MediaCodecInfo.java
@@ -2666,12 +2666,13 @@
public static final int HEVCHighTierLevel62 = 0x2000000;
// from OMX_VIDEO_DOLBYVISIONPROFILETYPE
- public static final int DolbyVisionProfileDvavDer = 0x1;
- public static final int DolbyVisionProfileDvavDen = 0x2;
- public static final int DolbyVisionProfileDvheDer = 0x3;
- public static final int DolbyVisionProfileDvheDen = 0x4;
- public static final int DolbyVisionProfileDvheDtr = 0x5;
- public static final int DolbyVisionProfileDvheStn = 0x6;
+ public static final int DolbyVisionProfileDvavPer = 0x1;
+ public static final int DolbyVisionProfileDvavPen = 0x2;
+ public static final int DolbyVisionProfileDvheDer = 0x4;
+ public static final int DolbyVisionProfileDvheDen = 0x8;
+ public static final int DolbyVisionProfileDvheDtr = 0x10;
+ public static final int DolbyVisionProfileDvheStn = 0x20;
+ public static final int DolbyVisionProfileDvheDth = 0x40;
// from OMX_VIDEO_DOLBYVISIONLEVELTYPE
public static final int DolbyVisionLevelHd24 = 0x1;
diff --git a/media/java/android/media/MediaExtractor.java b/media/java/android/media/MediaExtractor.java
index 177344a..24a400e4 100644
--- a/media/java/android/media/MediaExtractor.java
+++ b/media/java/android/media/MediaExtractor.java
@@ -275,16 +275,23 @@
return initDataMap.get(schemeUuid);
}
};
- } else if (formatMap.containsKey("crypto-key")) {
- ByteBuffer buf = (ByteBuffer) formatMap.get("crypto-key");
- buf.rewind();
- final byte[] data = new byte[buf.remaining()];
- buf.get(data);
- return new DrmInitData() {
- public SchemeInitData get(UUID schemeUuid) {
- return new DrmInitData.SchemeInitData("webm", data);
+ } else {
+ int numTracks = getTrackCount();
+ for (int i = 0; i < numTracks; ++i) {
+ Map<String, Object> trackFormatMap = getTrackFormatNative(i);
+ if (!trackFormatMap.containsKey("crypto-key")) {
+ continue;
}
- };
+ ByteBuffer buf = (ByteBuffer) trackFormatMap.get("crypto-key");
+ buf.rewind();
+ final byte[] data = new byte[buf.remaining()];
+ buf.get(data);
+ return new DrmInitData() {
+ public SchemeInitData get(UUID schemeUuid) {
+ return new DrmInitData.SchemeInitData("webm", data);
+ }
+ };
+ }
}
return null;
}
diff --git a/media/java/android/media/MediaMuxer.java b/media/java/android/media/MediaMuxer.java
index ebe509c..7117fbd 100644
--- a/media/java/android/media/MediaMuxer.java
+++ b/media/java/android/media/MediaMuxer.java
@@ -34,7 +34,7 @@
/**
* MediaMuxer facilitates muxing elementary streams. Currently supports mp4 or
* webm file as the output and at most one audio and/or one video elementary
- * stream.
+ * stream. MediaMuxer does not support muxing B-frames.
* <p>
* It is generally used like this:
*
diff --git a/media/java/android/media/browse/MediaBrowser.java b/media/java/android/media/browse/MediaBrowser.java
index c1805cb..7c6adad 100644
--- a/media/java/android/media/browse/MediaBrowser.java
+++ b/media/java/android/media/browse/MediaBrowser.java
@@ -72,7 +72,7 @@
/**
* Used as an int extra field to denote the page number to subscribe.
- * The value of {@code EXTRA_PAGE} should be greater than or equal to 1.
+ * The value of {@code EXTRA_PAGE} should be greater than or equal to 0.
*
* @see #EXTRA_PAGE_SIZE
*/
diff --git a/media/java/android/media/browse/MediaBrowserUtils.java b/media/java/android/media/browse/MediaBrowserUtils.java
index b06e598..2943e60 100644
--- a/media/java/android/media/browse/MediaBrowserUtils.java
+++ b/media/java/android/media/browse/MediaBrowserUtils.java
@@ -50,7 +50,7 @@
startIndex1 = 0;
endIndex1 = Integer.MAX_VALUE;
} else {
- startIndex1 = pageSize1 * (page1 - 1);
+ startIndex1 = pageSize1 * page1;
endIndex1 = startIndex1 + pageSize1 - 1;
}
@@ -58,7 +58,7 @@
startIndex2 = 0;
endIndex2 = Integer.MAX_VALUE;
} else {
- startIndex2 = pageSize2 * (page2 - 1);
+ startIndex2 = pageSize2 * page2;
endIndex2 = startIndex2 + pageSize2 - 1;
}
diff --git a/media/java/android/media/tv/TvInputInfo.java b/media/java/android/media/tv/TvInputInfo.java
index acf94f4c..03dc699 100644
--- a/media/java/android/media/tv/TvInputInfo.java
+++ b/media/java/android/media/tv/TvInputInfo.java
@@ -116,10 +116,10 @@
private final int mType;
private final boolean mIsHardwareInput;
- // TODO: Remove mLabel and mIconUri when createTvInputInfo() is removed.
- private String mLabel;
+ // TODO: Remove mIconUri when createTvInputInfo() is removed.
private Uri mIconUri;
+ private final CharSequence mLabel;
private final int mLabelResId;
private final Icon mIcon;
private final Icon mIconStandby;
@@ -161,8 +161,8 @@
TvInputInfo info = new TvInputInfo.Builder(context, service)
.setHdmiDeviceInfo(hdmiDeviceInfo)
.setParentId(parentId)
+ .setLabel(label)
.build();
- info.mLabel = label;
info.mIconUri = iconUri;
return info;
}
@@ -215,8 +215,8 @@
throws XmlPullParserException, IOException {
TvInputInfo info = new TvInputInfo.Builder(context, service)
.setTvInputHardwareInfo(hardwareInfo)
+ .setLabel(label)
.build();
- info.mLabel = label;
info.mIconUri = iconUri;
return info;
}
@@ -247,7 +247,7 @@
}
private TvInputInfo(ResolveInfo service, String id, int type, boolean isHardwareInput,
- int labelResId, Icon icon, Icon iconStandby, Icon iconDisconnected,
+ CharSequence label, int labelResId, Icon icon, Icon iconStandby, Icon iconDisconnected,
String setupActivity, String settingsActivity, boolean canRecord, int tunerCount,
HdmiDeviceInfo hdmiDeviceInfo, boolean isConnectedToHdmiSwitch, String parentId,
Bundle extras) {
@@ -255,6 +255,7 @@
mId = id;
mType = type;
mIsHardwareInput = isHardwareInput;
+ mLabel = label;
mLabelResId = labelResId;
mIcon = icon;
mIconStandby = iconStandby;
@@ -570,7 +571,7 @@
dest.writeString(mId);
dest.writeInt(mType);
dest.writeByte(mIsHardwareInput ? (byte) 1 : 0);
- dest.writeString(mLabel);
+ TextUtils.writeToParcel(mLabel, dest, flags);
dest.writeParcelable(mIconUri, flags);
dest.writeInt(mLabelResId);
dest.writeParcelable(mIcon, flags);
@@ -612,7 +613,7 @@
mId = in.readString();
mType = in.readInt();
mIsHardwareInput = in.readByte() == 1;
- mLabel = in.readString();
+ mLabel = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
mIconUri = in.readParcelable(null);
mLabelResId = in.readInt();
mIcon = in.readParcelable(null);
@@ -660,6 +661,7 @@
private final Context mContext;
private final ResolveInfo mResolveInfo;
+ private CharSequence mLabel;
private int mLabelResId;
private Icon mIcon;
private Icon mIconStandby;
@@ -746,12 +748,31 @@
/**
* Sets the label.
*
+ * @param label The text to be used as label.
+ * @return This Builder object to allow for chaining of calls to builder methods.
+ * @hide
+ */
+ @SystemApi
+ public Builder setLabel(CharSequence label) {
+ if (mLabelResId != 0) {
+ throw new IllegalStateException("Resource ID for label is already set.");
+ }
+ this.mLabel = label;
+ return this;
+ }
+
+ /**
+ * Sets the label.
+ *
* @param resId The resource ID of the text to use.
* @return This Builder object to allow for chaining of calls to builder methods.
* @hide
*/
@SystemApi
public Builder setLabel(int resId) {
+ if (mLabel != null) {
+ throw new IllegalStateException("Label text is already set.");
+ }
this.mLabelResId = resId;
return this;
}
@@ -868,8 +889,8 @@
type = TYPE_TUNER;
}
parseServiceMetadata(type);
- return new TvInputInfo(mResolveInfo, id, type, isHardwareInput, mLabelResId, mIcon,
- mIconStandby, mIconDisconnected, mSetupActivity, mSettingsActivity,
+ return new TvInputInfo(mResolveInfo, id, type, isHardwareInput, mLabel, mLabelResId,
+ mIcon, mIconStandby, mIconDisconnected, mSetupActivity, mSettingsActivity,
mCanRecord == null ? false : mCanRecord, mTunerCount == null ? 0 : mTunerCount,
mHdmiDeviceInfo, isConnectedToHdmiSwitch, mParentId, mExtras);
}
diff --git a/media/java/android/media/tv/TvInputManager.java b/media/java/android/media/tv/TvInputManager.java
index c72a7a0..b4536b1 100644
--- a/media/java/android/media/tv/TvInputManager.java
+++ b/media/java/android/media/tv/TvInputManager.java
@@ -56,7 +56,26 @@
/**
* Central system API to the overall TV input framework (TIF) architecture, which arbitrates
- * interaction between applications and the selected TV inputs.
+ * interaction between applications and the selected TV inputs. You can retrieve an instance of
+ * this interface with {@link android.content.Context#getSystemService
+ * Context.getSystemService(Context.TV_INPUT_SERVICE)}.
+ *
+ * <p>There are three primary parties involved in the TV input framework (TIF) architecture:
+ *
+ * <ul>
+ * <li>The <strong>TV input manager</strong> as expressed by this class is the central point of the
+ * system that manages interaction between all other parts. It is expressed as the client-side API
+ * here which exists in each application context and communicates with a global system service that
+ * manages the interaction across all processes.
+ * <li>A <strong>TV input</strong> implemented by {@link TvInputService} represents an input source
+ * of TV, which can be a pass-through input such as HDMI, or a tuner input which provides broadcast
+ * TV programs. The system binds to the TV input per application’s request.
+ * on implementing TV inputs.
+ * <li><strong>Applications</strong> talk to the TV input manager to list TV inputs and check their
+ * status. Once an application find the input to use, it uses {@link TvView} or
+ * {@link TvRecordingClient} for further interaction such as watching and recording broadcast TV
+ * programs.
+ * </ul>
*/
public final class TvInputManager {
private static final String TAG = "TvInputManager";
@@ -824,11 +843,21 @@
/**
* Interface used to receive events from Hardware objects.
+ *
* @hide
*/
@SystemApi
public abstract static class HardwareCallback {
+ /**
+ * This is called when {@link Hardware} is no longer available for the client.
+ */
public abstract void onReleased();
+
+ /**
+ * This is called when the underlying {@link TvStreamConfig} has been changed.
+ *
+ * @param configs The new {@link TvStreamConfig}s.
+ */
public abstract void onStreamConfigChanged(TvStreamConfig[] configs);
}
@@ -1470,18 +1499,41 @@
}
/**
- * Returns acquired TvInputManager.Hardware object for given deviceId.
+ * Acquires {@link Hardware} object for the given device ID.
*
- * If there are other Hardware object acquired for the same deviceId, calling this method will
- * preempt the previously acquired object and report {@link HardwareCallback#onReleased} to the
- * old object.
+ * <p>A subsequent call to this method on the same {@code deviceId} will release the currently
+ * acquired Hardware.
+ *
+ * @param deviceId The device ID to acquire Hardware for.
+ * @param callback A callback to receive updates on Hardware.
+ * @param info The TV input which will use the acquired Hardware.
+ * @return Hardware on success, {@code null} otherwise.
+ *
+ * @removed
+ */
+ @RequiresPermission(android.Manifest.permission.TV_INPUT_HARDWARE)
+ public Hardware acquireTvInputHardware(int deviceId, final HardwareCallback callback,
+ TvInputInfo info) {
+ return acquireTvInputHardware(deviceId, info, callback);
+ }
+
+ /**
+ * Acquires {@link Hardware} object for the given device ID.
+ *
+ * <p>A subsequent call to this method on the same {@code deviceId} will release the currently
+ * acquired Hardware.
+ *
+ * @param deviceId The device ID to acquire Hardware for.
+ * @param callback A callback to receive updates on Hardware.
+ * @param info The TV input which will use the acquired Hardware.
+ * @return Hardware on success, {@code null} otherwise.
*
* @hide
*/
@SystemApi
@RequiresPermission(android.Manifest.permission.TV_INPUT_HARDWARE)
- public Hardware acquireTvInputHardware(int deviceId, final HardwareCallback callback,
- TvInputInfo info) {
+ public Hardware acquireTvInputHardware(int deviceId, TvInputInfo info,
+ final HardwareCallback callback) {
try {
return new Hardware(
mService.acquireTvInputHardware(deviceId, new ITvInputHardwareCallback.Stub() {
@@ -1503,6 +1555,9 @@
/**
* Releases previously acquired hardware object.
*
+ * @param deviceId The device ID this Hardware was acquired for
+ * @param hardware Hardware to release.
+ *
* @hide
*/
@SystemApi
diff --git a/media/java/android/service/media/MediaBrowserService.java b/media/java/android/service/media/MediaBrowserService.java
index ae86632..6954045 100644
--- a/media/java/android/service/media/MediaBrowserService.java
+++ b/media/java/android/service/media/MediaBrowserService.java
@@ -657,9 +657,9 @@
if (page == -1 && pageSize == -1) {
return list;
}
- int fromIndex = pageSize * (page - 1);
+ int fromIndex = pageSize * page;
int toIndex = fromIndex + pageSize;
- if (page < 1 || pageSize < 1 || fromIndex >= list.size()) {
+ if (page < 0 || pageSize < 1 || fromIndex >= list.size()) {
return Collections.EMPTY_LIST;
}
if (toIndex > list.size()) {
diff --git a/media/jni/soundpool/SoundPool.cpp b/media/jni/soundpool/SoundPool.cpp
index b63df6f..d2dc440 100644
--- a/media/jni/soundpool/SoundPool.cpp
+++ b/media/jni/soundpool/SoundPool.cpp
@@ -554,6 +554,10 @@
if (bufidx >= 0) {
size_t bufsize;
uint8_t *buf = AMediaCodec_getInputBuffer(codec, bufidx, &bufsize);
+ if (buf == nullptr) {
+ ALOGE("AMediaCodec_getInputBuffer returned nullptr, short decode");
+ break;
+ }
int sampleSize = AMediaExtractor_readSampleData(ex, buf, bufsize);
ALOGV("read %d", sampleSize);
if (sampleSize < 0) {
@@ -563,10 +567,16 @@
}
int64_t presentationTimeUs = AMediaExtractor_getSampleTime(ex);
- AMediaCodec_queueInputBuffer(codec, bufidx,
+ media_status_t mstatus = AMediaCodec_queueInputBuffer(codec, bufidx,
0 /* offset */, sampleSize, presentationTimeUs,
sawInputEOS ? AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM : 0);
- AMediaExtractor_advance(ex);
+ if (mstatus != AMEDIA_OK) {
+ // AMEDIA_ERROR_UNKNOWN == { -ERANGE -EINVAL -EACCES }
+ ALOGE("AMediaCodec_queueInputBuffer returned status %d, short decode",
+ (int)mstatus);
+ break;
+ }
+ (void)AMediaExtractor_advance(ex);
}
}
@@ -581,6 +591,10 @@
ALOGV("got decoded buffer size %d", info.size);
uint8_t *buf = AMediaCodec_getOutputBuffer(codec, status, NULL /* out_size */);
+ if (buf == nullptr) {
+ ALOGE("AMediaCodec_getOutputBuffer returned nullptr, short decode");
+ break;
+ }
size_t dataSize = info.size;
if (dataSize > available) {
dataSize = available;
@@ -589,7 +603,14 @@
writePos += dataSize;
written += dataSize;
available -= dataSize;
- AMediaCodec_releaseOutputBuffer(codec, status, false /* render */);
+ media_status_t mstatus = AMediaCodec_releaseOutputBuffer(
+ codec, status, false /* render */);
+ if (mstatus != AMEDIA_OK) {
+ // AMEDIA_ERROR_UNKNOWN == { -ERANGE -EINVAL -EACCES }
+ ALOGE("AMediaCodec_releaseOutputBuffer returned status %d, short decode",
+ (int)mstatus);
+ break;
+ }
if (available == 0) {
// there might be more data, but there's no space for it
sawOutputEOS = true;
@@ -610,21 +631,21 @@
}
}
- AMediaCodec_stop(codec);
- AMediaCodec_delete(codec);
- AMediaExtractor_delete(ex);
+ (void)AMediaCodec_stop(codec);
+ (void)AMediaCodec_delete(codec);
+ (void)AMediaExtractor_delete(ex);
if (!AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_SAMPLE_RATE, (int32_t*) rate) ||
!AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_CHANNEL_COUNT, numChannels)) {
- AMediaFormat_delete(format);
+ (void)AMediaFormat_delete(format);
return UNKNOWN_ERROR;
}
- AMediaFormat_delete(format);
+ (void)AMediaFormat_delete(format);
*memsize = written;
return OK;
}
- AMediaFormat_delete(format);
+ (void)AMediaFormat_delete(format);
}
- AMediaExtractor_delete(ex);
+ (void)AMediaExtractor_delete(ex);
return UNKNOWN_ERROR;
}
diff --git a/media/tests/MediaFrameworkTest/res/values/exifinterface.xml b/media/tests/MediaFrameworkTest/res/values/exifinterface.xml
index d556ad3..3c5dd37 100644
--- a/media/tests/MediaFrameworkTest/res/values/exifinterface.xml
+++ b/media/tests/MediaFrameworkTest/res/values/exifinterface.xml
@@ -103,7 +103,7 @@
<item>600</item>
<item>800</item>
<item>1</item>
- <item />
+ <item>0</item>
</array>
<array name="volantis_jpg">
<item>false</item>
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/ExifInterfaceTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/ExifInterfaceTest.java
index 6207f7d..312d9aa 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/ExifInterfaceTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/ExifInterfaceTest.java
@@ -45,7 +45,7 @@
private static final String TAG = ExifInterface.class.getSimpleName();
private static final boolean VERBOSE = false; // lots of logging
- private static final double DIFFERENCE_TOLERANCE = .005;
+ private static final double DIFFERENCE_TOLERANCE = .001;
// List of files.
private static final String EXIF_BYTE_ORDER_II_JPEG = "image_exif_byte_order_ii.jpg";
@@ -61,7 +61,7 @@
private static final String[] EXIF_TAGS = {
ExifInterface.TAG_MAKE,
ExifInterface.TAG_MODEL,
- ExifInterface.TAG_APERTURE,
+ ExifInterface.TAG_F_NUMBER,
ExifInterface.TAG_DATETIME,
ExifInterface.TAG_EXPOSURE_TIME,
ExifInterface.TAG_FLASH,
@@ -77,7 +77,7 @@
ExifInterface.TAG_GPS_TIMESTAMP,
ExifInterface.TAG_IMAGE_LENGTH,
ExifInterface.TAG_IMAGE_WIDTH,
- ExifInterface.TAG_ISO,
+ ExifInterface.TAG_ISO_SPEED_RATINGS,
ExifInterface.TAG_ORIENTATION,
ExifInterface.TAG_WHITE_BALANCE
};
@@ -111,11 +111,11 @@
public final String gpsLongitudeRef;
public final String gpsProcessingMethod;
public final String gpsTimestamp;
- public final String imageLength;
- public final String imageWidth;
+ public final int imageLength;
+ public final int imageWidth;
public final String iso;
- public final String whiteBalance;
- public final String orientation;
+ public final int orientation;
+ public final int whiteBalance;
private static String getString(TypedArray typedArray, int index) {
String stringValue = typedArray.getString(index);
@@ -137,7 +137,7 @@
longitude = typedArray.getFloat(5, 0f);
altitude = typedArray.getFloat(6, 0f);
- // Read values.
+ // Reads values.
make = getString(typedArray, 7);
model = getString(typedArray, 8);
aperture = typedArray.getFloat(9, 0f);
@@ -154,11 +154,11 @@
gpsLongitudeRef = getString(typedArray, 20);
gpsProcessingMethod = getString(typedArray, 21);
gpsTimestamp = getString(typedArray, 22);
- imageLength = getString(typedArray, 23);
- imageWidth = getString(typedArray, 24);
+ imageLength = typedArray.getInt(23, 0);
+ imageWidth = typedArray.getInt(24, 0);
iso = getString(typedArray, 25);
- orientation = getString(typedArray, 26);
- whiteBalance = getString(typedArray, 27);
+ orientation = typedArray.getInt(26, 0);
+ whiteBalance = typedArray.getInt(27, 0);
typedArray.recycle();
}
@@ -208,11 +208,13 @@
+ bitmap.getHeight());
}
} else {
- Log.e(TAG, fileName + " Corrupted image (no thumbnail)");
+ Log.e(TAG, fileName + " Unexpected result: No thumbnails were found. "
+ + "A thumbnail is expected.");
}
} else {
if (exifInterface.getThumbnail() != null) {
- Log.e(TAG, fileName + " Corrupted image (a thumbnail exists)");
+ Log.e(TAG, fileName + " Unexpected result: A thumbnail was found. "
+ + "No thumbnail is expected.");
} else {
Log.v(TAG, fileName + " No thumbnail");
}
@@ -226,28 +228,27 @@
Log.v(TAG, fileName + " Latitude = " + latLong[0]);
Log.v(TAG, fileName + " Longitude = " + latLong[1]);
} else {
- Log.v(TAG, fileName + "No latlong data");
+ Log.v(TAG, fileName + " No latlong data");
}
// Prints values.
for (String tagKey : EXIF_TAGS) {
String tagValue = exifInterface.getAttribute(tagKey);
- Log.v(TAG, fileName + "Key{" + tagKey + "} = '" + tagValue + "'");
+ Log.v(TAG, fileName + " Key{" + tagKey + "} = '" + tagValue + "'");
}
}
- private void compareFloatTag(ExifInterface exifInterface, String tag, float expectedValue) {
- String stringValue = exifInterface.getAttribute(tag);
- float floatValue = 0f;
-
- if (stringValue != null) {
- floatValue = Float.parseFloat(stringValue);
- }
-
- assertEquals(expectedValue, floatValue, DIFFERENCE_TOLERANCE);
+ private void assertIntTag(ExifInterface exifInterface, String tag, int expectedValue) {
+ int intValue = exifInterface.getAttributeInt(tag, 0);
+ assertEquals(expectedValue, intValue);
}
- private void compareStringTag(ExifInterface exifInterface, String tag, String expectedValue) {
+ private void assertFloatTag(ExifInterface exifInterface, String tag, float expectedValue) {
+ double doubleValue = exifInterface.getAttributeDouble(tag, 0.0);
+ assertEquals(expectedValue, doubleValue, DIFFERENCE_TOLERANCE);
+ }
+
+ private void assertStringTag(ExifInterface exifInterface, String tag, String expectedValue) {
String stringValue = exifInterface.getAttribute(tag);
if (stringValue != null) {
stringValue = stringValue.trim();
@@ -257,7 +258,10 @@
}
private void compareWithExpectedValue(ExifInterface exifInterface,
- ExpectedValue expectedValue) {
+ ExpectedValue expectedValue, String verboseTag) {
+ if (VERBOSE) {
+ printExifTagsAndValues(verboseTag, exifInterface);
+ }
// Checks a thumbnail image.
assertEquals(expectedValue.hasThumbnail, exifInterface.hasThumbnail());
if (expectedValue.hasThumbnail) {
@@ -282,78 +286,144 @@
assertEquals(expectedValue.altitude, exifInterface.getAltitude(.0), DIFFERENCE_TOLERANCE);
// Checks values.
- compareStringTag(exifInterface, ExifInterface.TAG_MAKE, expectedValue.make);
- compareStringTag(exifInterface, ExifInterface.TAG_MODEL, expectedValue.model);
- compareFloatTag(exifInterface, ExifInterface.TAG_APERTURE, expectedValue.aperture);
- compareStringTag(exifInterface, ExifInterface.TAG_DATETIME, expectedValue.datetime);
- compareFloatTag(exifInterface, ExifInterface.TAG_EXPOSURE_TIME, expectedValue.exposureTime);
- compareFloatTag(exifInterface, ExifInterface.TAG_FLASH, expectedValue.flash);
- compareStringTag(exifInterface, ExifInterface.TAG_FOCAL_LENGTH, expectedValue.focalLength);
- compareStringTag(exifInterface, ExifInterface.TAG_GPS_ALTITUDE, expectedValue.gpsAltitude);
- compareStringTag(exifInterface, ExifInterface.TAG_GPS_ALTITUDE_REF,
+ assertStringTag(exifInterface, ExifInterface.TAG_MAKE, expectedValue.make);
+ assertStringTag(exifInterface, ExifInterface.TAG_MODEL, expectedValue.model);
+ assertFloatTag(exifInterface, ExifInterface.TAG_F_NUMBER, expectedValue.aperture);
+ assertStringTag(exifInterface, ExifInterface.TAG_DATETIME, expectedValue.datetime);
+ assertFloatTag(exifInterface, ExifInterface.TAG_EXPOSURE_TIME, expectedValue.exposureTime);
+ assertFloatTag(exifInterface, ExifInterface.TAG_FLASH, expectedValue.flash);
+ assertStringTag(exifInterface, ExifInterface.TAG_FOCAL_LENGTH, expectedValue.focalLength);
+ assertStringTag(exifInterface, ExifInterface.TAG_GPS_ALTITUDE, expectedValue.gpsAltitude);
+ assertStringTag(exifInterface, ExifInterface.TAG_GPS_ALTITUDE_REF,
expectedValue.gpsAltitudeRef);
- compareStringTag(exifInterface, ExifInterface.TAG_GPS_DATESTAMP,
- expectedValue.gpsDatestamp);
- compareStringTag(exifInterface, ExifInterface.TAG_GPS_LATITUDE, expectedValue.gpsLatitude);
- compareStringTag(exifInterface, ExifInterface.TAG_GPS_LATITUDE_REF,
+ assertStringTag(exifInterface, ExifInterface.TAG_GPS_DATESTAMP, expectedValue.gpsDatestamp);
+ assertStringTag(exifInterface, ExifInterface.TAG_GPS_LATITUDE, expectedValue.gpsLatitude);
+ assertStringTag(exifInterface, ExifInterface.TAG_GPS_LATITUDE_REF,
expectedValue.gpsLatitudeRef);
- compareStringTag(exifInterface, ExifInterface.TAG_GPS_LONGITUDE,
- expectedValue.gpsLongitude);
- compareStringTag(exifInterface, ExifInterface.TAG_GPS_LONGITUDE_REF,
+ assertStringTag(exifInterface, ExifInterface.TAG_GPS_LONGITUDE, expectedValue.gpsLongitude);
+ assertStringTag(exifInterface, ExifInterface.TAG_GPS_LONGITUDE_REF,
expectedValue.gpsLongitudeRef);
- compareStringTag(exifInterface, ExifInterface.TAG_GPS_PROCESSING_METHOD,
+ assertStringTag(exifInterface, ExifInterface.TAG_GPS_PROCESSING_METHOD,
expectedValue.gpsProcessingMethod);
- compareStringTag(exifInterface, ExifInterface.TAG_GPS_TIMESTAMP,
- expectedValue.gpsTimestamp);
- compareStringTag(exifInterface, ExifInterface.TAG_IMAGE_LENGTH, expectedValue.imageLength);
- compareStringTag(exifInterface, ExifInterface.TAG_IMAGE_WIDTH, expectedValue.imageWidth);
- compareStringTag(exifInterface, ExifInterface.TAG_ISO, expectedValue.iso);
- compareStringTag(exifInterface, ExifInterface.TAG_ORIENTATION, expectedValue.orientation);
- compareStringTag(exifInterface, ExifInterface.TAG_WHITE_BALANCE,
- expectedValue.whiteBalance);
+ assertStringTag(exifInterface, ExifInterface.TAG_GPS_TIMESTAMP, expectedValue.gpsTimestamp);
+ assertIntTag(exifInterface, ExifInterface.TAG_IMAGE_LENGTH, expectedValue.imageLength);
+ assertIntTag(exifInterface, ExifInterface.TAG_IMAGE_WIDTH, expectedValue.imageWidth);
+ assertStringTag(exifInterface, ExifInterface.TAG_ISO_SPEED_RATINGS, expectedValue.iso);
+ assertIntTag(exifInterface, ExifInterface.TAG_ORIENTATION, expectedValue.orientation);
+ assertIntTag(exifInterface, ExifInterface.TAG_WHITE_BALANCE, expectedValue.whiteBalance);
}
private void testExifInterfaceCommon(File imageFile, ExpectedValue expectedValue)
throws IOException {
- // Created via path.
+ String verboseTag = imageFile.getName();
+
+ // Creates via path.
ExifInterface exifInterface = new ExifInterface(imageFile.getAbsolutePath());
- if (VERBOSE) {
- printExifTagsAndValues(imageFile.getName(), exifInterface);
- }
- compareWithExpectedValue(exifInterface, expectedValue);
+ compareWithExpectedValue(exifInterface, expectedValue, verboseTag);
- // Created from an asset file.
- InputStream in = mContext.getAssets().open(imageFile.getName());
- exifInterface = new ExifInterface(in);
- if (VERBOSE) {
- printExifTagsAndValues(imageFile.getName(), exifInterface);
- }
- compareWithExpectedValue(exifInterface, expectedValue);
-
- // Created via InputStream.
- in = null;
+ // Creates from an asset file.
+ InputStream in = null;
try {
- in = new BufferedInputStream(new FileInputStream(imageFile.getAbsolutePath()));
+ in = mContext.getAssets().open(imageFile.getName());
exifInterface = new ExifInterface(in);
- if (VERBOSE) {
- printExifTagsAndValues(imageFile.getName(), exifInterface);
- }
- compareWithExpectedValue(exifInterface, expectedValue);
+ compareWithExpectedValue(exifInterface, expectedValue, verboseTag);
} finally {
IoUtils.closeQuietly(in);
}
- // Created via FileDescriptor.
+ // Creates via InputStream.
+ in = null;
try {
- FileDescriptor fd = Os.open(imageFile.getAbsolutePath(), OsConstants.O_RDONLY, 0600);
- exifInterface = new ExifInterface(fd);
- if (VERBOSE) {
- printExifTagsAndValues(imageFile.getName(), exifInterface);
- }
- compareWithExpectedValue(exifInterface, expectedValue);
- } catch (ErrnoException e) {
- e.rethrowAsIOException();
+ in = new BufferedInputStream(new FileInputStream(imageFile.getAbsolutePath()));
+ exifInterface = new ExifInterface(in);
+ compareWithExpectedValue(exifInterface, expectedValue, verboseTag);
+ } finally {
+ IoUtils.closeQuietly(in);
}
+
+ // Creates via FileDescriptor.
+ FileDescriptor fd = null;
+ try {
+ fd = Os.open(imageFile.getAbsolutePath(), OsConstants.O_RDONLY, 0600);
+ exifInterface = new ExifInterface(fd);
+ compareWithExpectedValue(exifInterface, expectedValue, verboseTag);
+ } catch (ErrnoException e) {
+ throw e.rethrowAsIOException();
+ } finally {
+ IoUtils.closeQuietly(fd);
+ }
+ }
+
+ private void testSaveAttributes_withFileName(File imageFile, ExpectedValue expectedValue)
+ throws IOException {
+ String verboseTag = imageFile.getName();
+
+ ExifInterface exifInterface = new ExifInterface(imageFile.getAbsolutePath());
+ exifInterface.saveAttributes();
+ exifInterface = new ExifInterface(imageFile.getAbsolutePath());
+ compareWithExpectedValue(exifInterface, expectedValue, verboseTag);
+
+ // Test for modifying one attribute.
+ String backupValue = exifInterface.getAttribute(ExifInterface.TAG_MAKE);
+ exifInterface.setAttribute(ExifInterface.TAG_MAKE, "abc");
+ exifInterface.saveAttributes();
+ exifInterface = new ExifInterface(imageFile.getAbsolutePath());
+ assertEquals("abc", exifInterface.getAttribute(ExifInterface.TAG_MAKE));
+ // Restore the backup value.
+ exifInterface.setAttribute(ExifInterface.TAG_MAKE, backupValue);
+ exifInterface.saveAttributes();
+ exifInterface = new ExifInterface(imageFile.getAbsolutePath());
+ compareWithExpectedValue(exifInterface, expectedValue, verboseTag);
+ }
+
+ private void testSaveAttributes_withFileDescriptor(File imageFile, ExpectedValue expectedValue)
+ throws IOException {
+ String verboseTag = imageFile.getName();
+
+ FileDescriptor fd = null;
+ try {
+ fd = Os.open(imageFile.getAbsolutePath(), OsConstants.O_RDWR, 0600);
+ ExifInterface exifInterface = new ExifInterface(fd);
+ exifInterface.saveAttributes();
+ Os.lseek(fd, 0, OsConstants.SEEK_SET);
+ exifInterface = new ExifInterface(fd);
+ compareWithExpectedValue(exifInterface, expectedValue, verboseTag);
+
+ // Test for modifying one attribute.
+ String backupValue = exifInterface.getAttribute(ExifInterface.TAG_MAKE);
+ exifInterface.setAttribute(ExifInterface.TAG_MAKE, "abc");
+ exifInterface.saveAttributes();
+ Os.lseek(fd, 0, OsConstants.SEEK_SET);
+ exifInterface = new ExifInterface(fd);
+ assertEquals("abc", exifInterface.getAttribute(ExifInterface.TAG_MAKE));
+ // Restore the backup value.
+ exifInterface.setAttribute(ExifInterface.TAG_MAKE, backupValue);
+ exifInterface.saveAttributes();
+ Os.lseek(fd, 0, OsConstants.SEEK_SET);
+ exifInterface = new ExifInterface(fd);
+ compareWithExpectedValue(exifInterface, expectedValue, verboseTag);
+ } catch (ErrnoException e) {
+ throw e.rethrowAsIOException();
+ } finally {
+ IoUtils.closeQuietly(fd);
+ }
+ }
+
+ private void testSaveAttributes_withInputStream(File imageFile, ExpectedValue expectedValue)
+ throws IOException {
+ InputStream in = null;
+ try {
+ in = getContext().getAssets().open(imageFile.getName());
+ ExifInterface exifInterface = new ExifInterface(in);
+ exifInterface.saveAttributes();
+ } catch (UnsupportedOperationException e) {
+ // Expected. saveAttributes is not supported with an ExifInterface object which was
+ // created with InputStream.
+ return;
+ } finally {
+ IoUtils.closeQuietly(in);
+ }
+ fail("Should not reach here!");
}
private void testExifInterfaceForJpeg(String fileName, int typedArrayResourceId)
@@ -366,30 +436,9 @@
testExifInterfaceCommon(imageFile, expectedValue);
// Test for saving attributes.
- ExifInterface exifInterface;
- try {
- FileDescriptor fd = Os.open(imageFile.getAbsolutePath(), OsConstants.O_RDWR, 0600);
- exifInterface = new ExifInterface(fd);
- exifInterface.saveAttributes();
- fd = Os.open(imageFile.getAbsolutePath(), OsConstants.O_RDWR, 0600);
- exifInterface = new ExifInterface(fd);
- if (VERBOSE) {
- printExifTagsAndValues(fileName, exifInterface);
- }
- compareWithExpectedValue(exifInterface, expectedValue);
- } catch (ErrnoException e) {
- e.rethrowAsIOException();
- }
-
- // Test for modifying one attribute.
- exifInterface = new ExifInterface(imageFile.getAbsolutePath());
- exifInterface.setAttribute(ExifInterface.TAG_MAKE, "abc");
- exifInterface.saveAttributes();
- exifInterface = new ExifInterface(imageFile.getAbsolutePath());
- if (VERBOSE) {
- printExifTagsAndValues(fileName, exifInterface);
- }
- assertEquals("abc", exifInterface.getAttribute(ExifInterface.TAG_MAKE));
+ testSaveAttributes_withFileName(imageFile, expectedValue);
+ testSaveAttributes_withFileDescriptor(imageFile, expectedValue);
+ testSaveAttributes_withInputStream(imageFile, expectedValue);
}
private void testExifInterfaceForRaw(String fileName, int typedArrayResourceId)
diff --git a/packages/CtsShim/Android.mk b/packages/CtsShim/Android.mk
new file mode 100644
index 0000000..537b171
--- /dev/null
+++ b/packages/CtsShim/Android.mk
@@ -0,0 +1,61 @@
+#
+# Copyright (C) 2016 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+LOCAL_PATH := $(call my-dir)
+
+###########################################################
+# Variant: Privileged app
+
+include $(CLEAR_VARS)
+# this needs to be a privileged application
+LOCAL_PRIVILEGED_MODULE := true
+
+LOCAL_MODULE_TAGS := optional
+LOCAL_SDK_VERSION := current
+LOCAL_PROGUARD_ENABLED := disabled
+LOCAL_DEX_PREOPT := false
+
+LOCAL_PACKAGE_NAME := CtsShimPriv
+
+#TODO need to find the correct certificate
+#Change in conjunction with cts/hostsidetests/appsecurity/test-apps/IntentFilterApp
+LOCAL_CERTIFICATE := platform
+LOCAL_MANIFEST_FILE := priv_shim/AndroidManifest.xml
+
+include $(BUILD_PACKAGE)
+
+
+
+###########################################################
+# Variant: System app
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := optional
+LOCAL_SDK_VERSION := current
+LOCAL_PROGUARD_ENABLED := disabled
+LOCAL_DEX_PREOPT := false
+
+LOCAL_PACKAGE_NAME := CtsShim
+
+#TODO need to find the correct certificate
+#Change in conjunction with cts/hostsidetests/appsecurity/test-apps/IntentFilterApp
+LOCAL_CERTIFICATE := platform
+LOCAL_MANIFEST_FILE := shim/AndroidManifest.xml
+
+include $(BUILD_PACKAGE)
+
+
diff --git a/packages/CtsShim/priv_shim/AndroidManifest.xml b/packages/CtsShim/priv_shim/AndroidManifest.xml
new file mode 100644
index 0000000..0a3f823
--- /dev/null
+++ b/packages/CtsShim/priv_shim/AndroidManifest.xml
@@ -0,0 +1,157 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<!-- Manifest for the privileged CTS shim -->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.cts.priv.ctsshim">
+ <application android:label="CtsShim">
+
+ <!-- These activities don't actually exist; define them just to test the filters !-->
+
+ <!-- install test; [some] high priority filters granted -->
+ <activity android:name=".InstallPriority">
+ <!-- normal actions; priority will be granted -->
+ <intent-filter android:priority="100">
+ <action android:name="android.intent.action.SEARCH" />
+ <category android:name="android.intent.category.INFO" />
+ </intent-filter>
+
+ <!-- protected actions; priority will be denied -->
+ <intent-filter android:priority="100">
+ <action android:name="android.intent.action.VIEW" />
+ <category android:name="android.intent.category.BROWSABLE" />
+ </intent-filter>
+ <intent-filter android:priority="100">
+ <action android:name="android.intent.action.SEND" />
+ </intent-filter>
+ <intent-filter android:priority="100">
+ <action android:name="android.intent.action.SEND_MULTIPLE" />
+ </intent-filter>
+ <intent-filter android:priority="100">
+ <action android:name="android.intent.action.SENDTO" />
+ </intent-filter>
+ </activity>
+
+ <!-- upgrade test; single, equivalent filter -->
+ <activity android:name=".UpgradeMatch">
+ <intent-filter android:priority="100">
+ <action android:name="com.android.cts.action.MATCH" />
+ <category android:name="android.intent.category.INFO" />
+ </intent-filter>
+ </activity>
+
+ <!-- upgrade test; multiple, equivalent filters -->
+ <activity android:name=".UpgradeMatchMultiple">
+ <intent-filter android:priority="100">
+ <action android:name="com.android.cts.action.MATCH_MULTIPLE" />
+ <category android:name="android.intent.category.INFO" />
+ </intent-filter>
+
+ <intent-filter android:priority="150">
+ <action android:name="com.android.cts.action.MATCH_MULTIPLE" />
+ <category android:name="android.intent.category.DEFAULT" />
+ <data android:scheme="http" />
+ <data android:scheme="https" />
+ <data android:host="www.google.com" android:port="80" />
+ <data android:host="www.google.com" android:port="8080" />
+ <data android:host="goo.gl" android:port="443" />
+ </intent-filter>
+ </activity>
+
+ <!-- upgrade test; lower priority -->
+ <activity android:name=".UpgradeLowerPriority">
+ <intent-filter android:priority="100">
+ <action android:name="com.android.cts.action.LOWER_PRIORITY" />
+ <category android:name="android.intent.category.INFO" />
+ </intent-filter>
+ </activity>
+
+ <!-- upgrade test; action subset -->
+ <activity android:name=".UpgradeActionSubset">
+ <intent-filter android:priority="100">
+ <action android:name="com.android.cts.action.ACTION_SUB" />
+ <action android:name="com.android.cts.action.ACTION_SUB_2" />
+ <action android:name="com.android.cts.action.ACTION_SUB_3" />
+ <category android:name="android.intent.category.DEFAULT" />
+ </intent-filter>
+ </activity>
+
+ <!-- upgrade test; category subset -->
+ <activity android:name=".UpgradeCategorySubset">
+ <intent-filter android:priority="100">
+ <action android:name="com.android.cts.action.CATEGORY_SUB" />
+ <category android:name="android.intent.category.INFO" />
+ <category android:name="android.intent.category.DEFAULT" />
+ </intent-filter>
+ </activity>
+
+ <!-- upgrade test; scheme subset -->
+ <activity android:name=".UpgradeSchemeSubset">
+ <intent-filter android:priority="100">
+ <action android:name="com.android.cts.action.SCHEME_SUB" />
+ <data android:scheme="content" />
+ <data android:scheme="flubber" />
+ <data android:scheme="zoodle" />
+ </intent-filter>
+ </activity>
+
+ <!-- upgrade test; authority subset -->
+ <activity android:name=".UpgradeAuthoritySubset">
+ <intent-filter android:priority="100">
+ <action android:name="com.android.cts.action.AUTHORITY_SUB" />
+ <data android:host="www.google.com" android:port="80" />
+ <data android:host="www.google.com" android:port="8080" />
+ <data android:host="mail.google.com" android:port="80" />
+ <data android:host="goo.gl" android:port="443" />
+ </intent-filter>
+ </activity>
+
+
+ <!-- upgrade test; new action -->
+ <activity android:name=".UpgradeNewAction">
+ <intent-filter android:priority="100">
+ <action android:name="com.android.cts.action.NEW_ACTION" />
+ <category android:name="android.intent.category.DEFAULT" />
+ </intent-filter>
+ </activity>
+
+ <!-- upgrade test; new category -->
+ <activity android:name=".UpgradeNewCategory">
+ <intent-filter android:priority="100">
+ <action android:name="com.android.cts.action.NEW_CATEGORY" />
+ <category android:name="android.intent.category.DEFAULT" />
+ </intent-filter>
+ </activity>
+
+ <!-- upgrade test; new scheme -->
+ <activity android:name=".UpgradeNewScheme">
+ <intent-filter android:priority="100">
+ <action android:name="com.android.cts.action.NEW_SCHEME" />
+ <data android:scheme="content" />
+ </intent-filter>
+ </activity>
+
+ <!-- upgrade test; new authority -->
+ <activity android:name=".UpgradeNewAuthority">
+ <intent-filter android:priority="100">
+ <action android:name="com.android.cts.action.NEW_AUTHORITY" />
+ <data android:host="www.google.com" android:port="80" />
+ </intent-filter>
+ </activity>
+
+ </application>
+</manifest>
+
diff --git a/packages/CtsShim/shim/AndroidManifest.xml b/packages/CtsShim/shim/AndroidManifest.xml
new file mode 100644
index 0000000..ee4b547
--- /dev/null
+++ b/packages/CtsShim/shim/AndroidManifest.xml
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<!-- Manifest for the system CTS shim -->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.cts.system.ctsshim">
+ <application android:label="CtsShim">
+
+ <!-- These activities don't actually exist; define them just to test the filters !-->
+
+ <!-- install test; high priority filter DENIED -->
+ <activity android:name=".InstallPriority">
+ <intent-filter android:priority="100">
+ <action android:name="android.intent.action.SEARCH" />
+ <category android:name="android.intent.category.INFO" />
+ </intent-filter>
+ <intent-filter android:priority="100">
+ <action android:name="android.intent.action.VIEW" />
+ <category android:name="android.intent.category.BROWSABLE" />
+ </intent-filter>
+ <intent-filter android:priority="100">
+ <action android:name="android.intent.action.SEND" />
+ </intent-filter>
+ <intent-filter android:priority="100">
+ <action android:name="android.intent.action.SEND_MULTIPLE" />
+ </intent-filter>
+ <intent-filter android:priority="100">
+ <action android:name="android.intent.action.SENDTO" />
+ </intent-filter>
+ </activity>
+
+ </application>
+</manifest>
+
diff --git a/packages/DocumentsUI/app-perf-tests/AndroidManifest.xml b/packages/DocumentsUI/app-perf-tests/AndroidManifest.xml
index 1c3ed80..0013b6b 100644
--- a/packages/DocumentsUI/app-perf-tests/AndroidManifest.xml
+++ b/packages/DocumentsUI/app-perf-tests/AndroidManifest.xml
@@ -2,6 +2,8 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.documentsui.appperftests">
+ <uses-permission android:name="android.permission.KILL_BACKGROUND_PROCESSES" />
+
<application>
<uses-library android:name="android.test.runner" />
diff --git a/packages/DocumentsUI/app-perf-tests/src/com/android/documentsui/FilesAppPerfTest.java b/packages/DocumentsUI/app-perf-tests/src/com/android/documentsui/FilesAppPerfTest.java
index d6e8a96..ce2fc13 100644
--- a/packages/DocumentsUI/app-perf-tests/src/com/android/documentsui/FilesAppPerfTest.java
+++ b/packages/DocumentsUI/app-perf-tests/src/com/android/documentsui/FilesAppPerfTest.java
@@ -17,6 +17,8 @@
package com.android.documentsui;
import android.app.Activity;
+import android.app.ActivityManager;
+import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
@@ -91,12 +93,15 @@
}
private void killProviders() throws Exception {
- final PackageManager pm = getInstrumentation().getContext().getPackageManager();
+ final Context context = getInstrumentation().getContext();
+ final PackageManager pm = context.getPackageManager();
+ final ActivityManager am = (ActivityManager) context.getSystemService(
+ Context.ACTIVITY_SERVICE);
final Intent intent = new Intent(DocumentsContract.PROVIDER_INTERFACE);
final List<ResolveInfo> providers = pm.queryIntentContentProviders(intent, 0);
for (ResolveInfo info : providers) {
final String packageName = info.providerInfo.packageName;
- mDevice.executeShellCommand("am force-stop " + packageName);
+ am.killBackgroundProcesses(packageName);
}
}
}
diff --git a/packages/DocumentsUI/perf-tests/Android.mk b/packages/DocumentsUI/perf-tests/Android.mk
index 11c163b..5ebf85f 100644
--- a/packages/DocumentsUI/perf-tests/Android.mk
+++ b/packages/DocumentsUI/perf-tests/Android.mk
@@ -2,8 +2,8 @@
include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := tests
-#LOCAL_SDK_VERSION := current
+LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
LOCAL_SRC_FILES := $(call all-java-files-under, src) \
$(call all-java-files-under, ../tests/src/com/android/documentsui/bots) \
../tests/src/com/android/documentsui/ActivityTest.java \
@@ -11,7 +11,7 @@
../tests/src/com/android/documentsui/StubProvider.java
LOCAL_JAVA_LIBRARIES := android-support-v4 android.test.runner
-LOCAL_STATIC_JAVA_LIBRARIES := mockito-target ub-uiautomator
+LOCAL_STATIC_JAVA_LIBRARIES := mockito-target ub-uiautomator ub-janktesthelper
LOCAL_PACKAGE_NAME := DocumentsUIPerfTests
LOCAL_INSTRUMENTATION_FOR := DocumentsUI
diff --git a/packages/DocumentsUI/perf-tests/res/raw/earth_small.jpg b/packages/DocumentsUI/perf-tests/res/raw/earth_small.jpg
new file mode 100644
index 0000000..dd2da3e
--- /dev/null
+++ b/packages/DocumentsUI/perf-tests/res/raw/earth_small.jpg
Binary files differ
diff --git a/packages/DocumentsUI/perf-tests/src/com/android/documentsui/FilesJankPerfTest.java b/packages/DocumentsUI/perf-tests/src/com/android/documentsui/FilesJankPerfTest.java
new file mode 100644
index 0000000..cb2d904
--- /dev/null
+++ b/packages/DocumentsUI/perf-tests/src/com/android/documentsui/FilesJankPerfTest.java
@@ -0,0 +1,90 @@
+/*
+ * 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.documentsui;
+
+import static com.android.documentsui.StressProvider.DEFAULT_AUTHORITY;
+import static com.android.documentsui.StressProvider.STRESS_ROOT_0_ID;
+import static com.android.documentsui.StressProvider.STRESS_ROOT_2_ID;
+
+import android.app.Activity;
+import android.os.RemoteException;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import android.content.Intent;
+import android.content.Context;
+import android.support.test.jank.JankTest;
+import android.support.test.jank.JankTestBase;
+import android.support.test.uiautomator.UiDevice;
+import android.support.test.jank.GfxMonitor;
+import android.support.test.uiautomator.UiScrollable;
+import android.util.Log;
+
+import com.android.documentsui.FilesActivity;
+import com.android.documentsui.bots.RootsListBot;
+import com.android.documentsui.bots.DirectoryListBot;
+
+@LargeTest
+public class FilesJankPerfTest extends JankTestBase {
+ private static final String DOCUMENTSUI_PACKAGE = "com.android.documentsui";
+ private static final int MAX_FLINGS = 10;
+ private static final int BOT_TIMEOUT = 5000;
+
+ private RootsListBot mRootsListBot;
+ private DirectoryListBot mDirListBot;
+ private Activity mActivity = null;
+
+ public void setUpInLoop() {
+ final UiDevice device = UiDevice.getInstance(getInstrumentation());
+ final Context context = getInstrumentation().getTargetContext();
+ mRootsListBot = new RootsListBot(device, context, BOT_TIMEOUT);
+ mDirListBot = new DirectoryListBot(device, context, BOT_TIMEOUT);
+
+ final Intent intent = new Intent(context, FilesActivity.class);
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ mActivity = getInstrumentation().startActivitySync(intent);
+ }
+
+ public void tearDownInLoop() {
+ if (mActivity != null) {
+ mActivity.finish();
+ mActivity = null;
+ }
+ }
+
+ public void setupAndOpenInLoop() throws Exception {
+ setUpInLoop();
+ openRoot();
+ }
+
+ public void openRoot() throws Exception {
+ mRootsListBot.openRoot(STRESS_ROOT_2_ID);
+ }
+
+ @JankTest(expectedFrames=0, beforeLoop="setUpInLoop", afterLoop="tearDownInLoop")
+ @GfxMonitor(processName=DOCUMENTSUI_PACKAGE)
+ public void testOpenRootJankPerformance() throws Exception {
+ openRoot();
+ getInstrumentation().waitForIdleSync();
+ }
+
+ @JankTest(expectedFrames=0, beforeLoop="setupAndOpenInLoop", afterLoop="tearDownInLoop")
+ @GfxMonitor(processName=DOCUMENTSUI_PACKAGE)
+ public void testFlingJankPerformance() throws Exception {
+ new UiScrollable(mDirListBot.findDocumentsList().getSelector()).flingToEnd(MAX_FLINGS);
+ getInstrumentation().waitForIdleSync();
+ }
+}
diff --git a/packages/DocumentsUI/perf-tests/src/com/android/documentsui/StressProvider.java b/packages/DocumentsUI/perf-tests/src/com/android/documentsui/StressProvider.java
index 1bc802a..f9b06f8 100644
--- a/packages/DocumentsUI/perf-tests/src/com/android/documentsui/StressProvider.java
+++ b/packages/DocumentsUI/perf-tests/src/com/android/documentsui/StressProvider.java
@@ -18,9 +18,11 @@
import android.content.Context;
import android.content.pm.ProviderInfo;
+import android.content.res.AssetFileDescriptor;
import android.database.Cursor;
import android.database.MatrixCursor.RowBuilder;
import android.database.MatrixCursor;
+import android.graphics.Point;
import android.os.CancellationSignal;
import android.os.FileUtils;
import android.os.ParcelFileDescriptor;
@@ -31,8 +33,11 @@
import java.io.File;
import java.io.FileNotFoundException;
+import java.io.IOException;
import java.util.ArrayList;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
import java.util.Random;
/**
@@ -46,11 +51,21 @@
// Empty root.
public static final String STRESS_ROOT_0_ID = "STRESS_ROOT_0";
- // Root with thousands of items.
+ // Root with thousands of directories.
public static final String STRESS_ROOT_1_ID = "STRESS_ROOT_1";
+ // Root with hundreds of files.
+ public static final String STRESS_ROOT_2_ID = "STRESS_ROOT_2";
+
private static final String STRESS_ROOT_0_DOC_ID = "STRESS_ROOT_0_DOC";
private static final String STRESS_ROOT_1_DOC_ID = "STRESS_ROOT_1_DOC";
+ private static final String STRESS_ROOT_2_DOC_ID = "STRESS_ROOT_2_DOC";
+
+ private static final int STRESS_ROOT_1_ITEMS = 10000;
+ private static final int STRESS_ROOT_2_ITEMS = 300;
+
+ private static final String MIME_TYPE_IMAGE = "image/jpeg";
+ private static final long REFERENCE_TIMESTAMP = 1459159369359L;
private static final String[] DEFAULT_ROOT_PROJECTION = new String[] {
Root.COLUMN_ROOT_ID, Root.COLUMN_FLAGS, Root.COLUMN_TITLE, Root.COLUMN_DOCUMENT_ID,
@@ -62,7 +77,12 @@
};
private String mAuthority = DEFAULT_AUTHORITY;
- private ArrayList<String> mIds = new ArrayList<>();
+
+ // Map from a root document id to children document ids.
+ private Map<String, ArrayList<StubDocument>> mChildDocuments = new HashMap<>();
+
+ private Map<String, StubDocument> mDocuments = new HashMap<>();
+ private Map<String, StubRoot> mRoots = new HashMap<>();
@Override
public void attachInfo(Context context, ProviderInfo info) {
@@ -72,20 +92,48 @@
@Override
public boolean onCreate() {
- mIds = new ArrayList();
- for (int i = 0; i < 10000; i++) {
- mIds.add(createRandomId(i));
+ StubDocument document;
+
+ ArrayList<StubDocument> children = new ArrayList<StubDocument>();
+ mChildDocuments.put(STRESS_ROOT_1_DOC_ID, children);
+ for (int i = 0; i < STRESS_ROOT_1_ITEMS; i++) {
+ document = StubDocument.createDirectory(i);
+ mDocuments.put(document.id, document);
+ children.add(document);
}
- mIds.add(STRESS_ROOT_0_DOC_ID);
- mIds.add(STRESS_ROOT_1_DOC_ID);
+
+ children = new ArrayList<StubDocument>();
+ mChildDocuments.put(STRESS_ROOT_2_DOC_ID, children);
+ for (int i = 0; i < STRESS_ROOT_2_ITEMS; i++) {
+ try {
+ document = StubDocument.createFile(
+ getContext(), MIME_TYPE_IMAGE,
+ com.android.documentsui.perftests.R.raw.earth_small,
+ STRESS_ROOT_1_ITEMS + i);
+ } catch (IOException e) {
+ return false;
+ }
+ mDocuments.put(document.id, document);
+ children.add(document);
+ }
+
+ mRoots.put(STRESS_ROOT_0_ID, new StubRoot(STRESS_ROOT_0_ID, STRESS_ROOT_0_DOC_ID));
+ mRoots.put(STRESS_ROOT_1_ID, new StubRoot(STRESS_ROOT_1_ID, STRESS_ROOT_1_DOC_ID));
+ mRoots.put(STRESS_ROOT_2_ID, new StubRoot(STRESS_ROOT_2_ID, STRESS_ROOT_2_DOC_ID));
+
+ mDocuments.put(STRESS_ROOT_0_DOC_ID, StubDocument.createDirectory(STRESS_ROOT_0_DOC_ID));
+ mDocuments.put(STRESS_ROOT_1_DOC_ID, StubDocument.createDirectory(STRESS_ROOT_1_DOC_ID));
+ mDocuments.put(STRESS_ROOT_2_DOC_ID, StubDocument.createDirectory(STRESS_ROOT_2_DOC_ID));
+
return true;
}
@Override
public Cursor queryRoots(String[] projection) throws FileNotFoundException {
final MatrixCursor result = new MatrixCursor(DEFAULT_ROOT_PROJECTION);
- includeRoot(result, STRESS_ROOT_0_ID, STRESS_ROOT_0_DOC_ID);
- includeRoot(result, STRESS_ROOT_1_ID, STRESS_ROOT_1_DOC_ID);
+ for (StubRoot root : mRoots.values()) {
+ includeRoot(result, root);
+ }
return result;
}
@@ -93,57 +141,125 @@
public Cursor queryDocument(String documentId, String[] projection)
throws FileNotFoundException {
final MatrixCursor result = new MatrixCursor(DEFAULT_DOCUMENT_PROJECTION);
- includeDocument(result, documentId);
+ final StubDocument document = mDocuments.get(documentId);
+ includeDocument(result, document);
return result;
}
@Override
- public Cursor queryChildDocuments(String parentDocumentId, String[] projection, String sortOrder)
+ public Cursor queryChildDocuments(String parentDocumentId, String[] projection,
+ String sortOrder)
throws FileNotFoundException {
final MatrixCursor result = new MatrixCursor(DEFAULT_DOCUMENT_PROJECTION);
- if (STRESS_ROOT_1_DOC_ID.equals(parentDocumentId)) {
- for (String id : mIds) {
- includeDocument(result, id);
+ final ArrayList<StubDocument> childDocuments = mChildDocuments.get(parentDocumentId);
+ if (childDocuments != null) {
+ for (StubDocument document : childDocuments) {
+ includeDocument(result, document);
}
}
return result;
}
@Override
- public ParcelFileDescriptor openDocument(String docId, String mode, CancellationSignal signal)
+ public AssetFileDescriptor openDocumentThumbnail(String docId, Point sizeHint,
+ CancellationSignal signal)
+ throws FileNotFoundException {
+ final StubDocument document = mDocuments.get(docId);
+ return getContext().getResources().openRawResourceFd(document.thumbnail);
+ }
+
+ @Override
+ public ParcelFileDescriptor openDocument(String docId, String mode,
+ CancellationSignal signal)
throws FileNotFoundException {
throw new UnsupportedOperationException();
}
- private void includeRoot(MatrixCursor result, String rootId, String docId) {
+ private void includeRoot(MatrixCursor result, StubRoot root) {
final RowBuilder row = result.newRow();
- row.add(Root.COLUMN_ROOT_ID, rootId);
+ row.add(Root.COLUMN_ROOT_ID, root.id);
row.add(Root.COLUMN_FLAGS, 0);
- row.add(Root.COLUMN_TITLE, rootId);
- row.add(Root.COLUMN_DOCUMENT_ID, docId);
+ row.add(Root.COLUMN_TITLE, root.id);
+ row.add(Root.COLUMN_DOCUMENT_ID, root.documentId);
}
- private void includeDocument(MatrixCursor result, String id) {
+ private void includeDocument(MatrixCursor result, StubDocument document) {
final RowBuilder row = result.newRow();
- row.add(Document.COLUMN_DOCUMENT_ID, id);
- row.add(Document.COLUMN_DISPLAY_NAME, id);
- row.add(Document.COLUMN_SIZE, 0);
- row.add(Document.COLUMN_MIME_TYPE, DocumentsContract.Document.MIME_TYPE_DIR);
- row.add(Document.COLUMN_FLAGS, 0);
- row.add(Document.COLUMN_LAST_MODIFIED, null);
+ row.add(Document.COLUMN_DOCUMENT_ID, document.id);
+ row.add(Document.COLUMN_DISPLAY_NAME, document.id);
+ row.add(Document.COLUMN_SIZE, document.size);
+ row.add(Document.COLUMN_MIME_TYPE, document.mimeType);
+ row.add(Document.COLUMN_FLAGS,
+ document.thumbnail != -1 ? Document.FLAG_SUPPORTS_THUMBNAIL : 0);
+ row.add(Document.COLUMN_LAST_MODIFIED, document.lastModified);
}
- private static String getDocumentIdForFile(File file) {
+ private static String getStubDocumentIdForFile(File file) {
return file.getAbsolutePath();
}
- private String createRandomId(int index) {
- final Random random = new Random(index);
- final StringBuilder builder = new StringBuilder();
- for (int i = 0; i < 20; i++) {
- builder.append((char) (random.nextInt(96) + 32));
+ private static class StubDocument {
+ final String mimeType;
+ final String id;
+ final int size;
+ final long lastModified;
+ final int thumbnail;
+
+ private StubDocument(String mimeType, String id, int size, long lastModified,
+ int thumbnail) {
+ this.mimeType = mimeType;
+ this.id = id;
+ this.size = size;
+ this.lastModified = lastModified;
+ this.thumbnail = thumbnail;
}
- builder.append(index); // Append a number to guarantee uniqueness.
- return builder.toString();
+
+ public static StubDocument createDirectory(int index) {
+ return new StubDocument(
+ DocumentsContract.Document.MIME_TYPE_DIR, createRandomId(index), 0,
+ createRandomTime(index), -1);
+ }
+
+ public static StubDocument createDirectory(String id) {
+ return new StubDocument(DocumentsContract.Document.MIME_TYPE_DIR, id, 0, 0, -1);
+ }
+
+ public static StubDocument createFile(Context context, String mimeType, int thumbnail,
+ int index) throws IOException {
+ return new StubDocument(
+ mimeType, createRandomId(index), createRandomSize(index),
+ createRandomTime(index), thumbnail);
+ }
+
+ private static String createRandomId(int index) {
+ final Random random = new Random(index);
+ final StringBuilder builder = new StringBuilder();
+ for (int i = 0; i < 20; i++) {
+ builder.append((char) (random.nextInt(96) + 32));
+ }
+ builder.append(index); // Append a number to guarantee uniqueness.
+ return builder.toString();
+ }
+
+ private static int createRandomSize(int index) {
+ final Random random = new Random(index);
+ return random.nextInt(1024 * 1024 * 100); // Up to 100 MB.
+ }
+
+ private static long createRandomTime(int index) {
+ final Random random = new Random(index);
+ // Up to 30 days backwards from REFERENCE_TIMESTAMP.
+ return REFERENCE_TIMESTAMP - random.nextLong() % 1000L * 60 * 60 * 24 * 30;
+ }
+ }
+
+ private static class StubRoot {
+ final String id;
+ final String documentId;
+
+ public StubRoot(String id, String documentId) {
+ this.id = id;
+ this.documentId = documentId;
+ }
}
}
diff --git a/packages/DocumentsUI/res/menu/activity.xml b/packages/DocumentsUI/res/menu/activity.xml
index 2aee569..85e7a7a 100644
--- a/packages/DocumentsUI/res/menu/activity.xml
+++ b/packages/DocumentsUI/res/menu/activity.xml
@@ -31,61 +31,68 @@
android:actionViewClass="android.widget.SearchView"
android:imeOptions="actionSearch"
android:visible="false" />
- <item
- android:id="@+id/menu_grid"
- android:title="@string/menu_grid"
- android:icon="@drawable/ic_menu_view_grid"
- android:showAsAction="always" />
- <item
- android:id="@+id/menu_list"
- android:title="@string/menu_list"
- android:icon="@drawable/ic_menu_view_list"
- android:showAsAction="always" />
+<!-- This group is being hidden when searching is in full bar mode-->
+ <group android:id="@+id/group_hide_when_searching">
+ <item
+ android:id="@+id/menu_grid"
+ android:title="@string/menu_grid"
+ android:icon="@drawable/ic_menu_view_grid"
+ android:showAsAction="always" />
+ <item
+ android:id="@+id/menu_list"
+ android:title="@string/menu_list"
+ android:icon="@drawable/ic_menu_view_list"
+ android:showAsAction="always" />
- <item
- android:id="@+id/menu_new_window"
- android:title="@string/menu_new_window"
- android:alphabeticShortcut="n"
- android:showAsAction="never"
- android:visible="false" />
- <item
- android:id="@+id/menu_create_dir"
- android:title="@string/menu_create_dir"
- android:icon="@drawable/ic_menu_new_folder"
- android:alphabeticShortcut="e"
- android:showAsAction="never"
- android:visible="false" />
- <item
- android:id="@+id/menu_paste_from_clipboard"
- android:title="@string/menu_paste_from_clipboard"
- android:alphabeticShortcut="v"
- android:showAsAction="never"
- android:visible="false" />
- <!-- Copy action is defined in mode_directory.xml -->
- <item
- android:id="@+id/menu_sort"
- android:title="@string/menu_sort"
- android:icon="@drawable/ic_menu_sortby"
- android:showAsAction="ifRoom">
- <menu>
- <item
- android:id="@+id/menu_sort_name"
- android:title="@string/sort_name" />
- <item
- android:id="@+id/menu_sort_date"
- android:title="@string/sort_date" />
- <item
- android:id="@+id/menu_sort_size"
- android:title="@string/sort_size" />
- </menu>
- </item>
- <item
- android:id="@+id/menu_file_size"
- android:showAsAction="never"
- android:visible="false" />
- <item
- android:id="@+id/menu_settings"
- android:title="@string/menu_settings"
- android:showAsAction="never"
- android:visible="false" />
+ <item
+ android:id="@+id/menu_new_window"
+ android:title="@string/menu_new_window"
+ android:alphabeticShortcut="n"
+ android:showAsAction="never"
+ android:visible="false" />
+ <item
+ android:id="@+id/menu_create_dir"
+ android:title="@string/menu_create_dir"
+ android:icon="@drawable/ic_menu_new_folder"
+ android:alphabeticShortcut="e"
+ android:showAsAction="never"
+ android:visible="false" />
+ <item
+ android:id="@+id/menu_paste_from_clipboard"
+ android:title="@string/menu_paste_from_clipboard"
+ android:alphabeticShortcut="v"
+ android:showAsAction="never"
+ android:visible="false" />
+ <!-- Copy action is defined in mode_directory.xml -->
+ <item
+ android:id="@+id/menu_sort"
+ android:title="@string/menu_sort"
+ android:icon="@drawable/ic_menu_sortby"
+ android:showAsAction="ifRoom">
+ <menu>
+ <item
+ android:id="@+id/menu_sort_name"
+ android:title="@string/sort_name" />
+ <item
+ android:id="@+id/menu_sort_date"
+ android:title="@string/sort_date" />
+ <item
+ android:id="@+id/menu_sort_size"
+ android:title="@string/sort_size" />
+ </menu>
+ </item>
+ <item
+ android:id="@+id/menu_file_size"
+ android:showAsAction="never"
+ android:visible="false" />
+ <item
+ android:id="@+id/menu_advanced"
+ android:showAsAction="never"
+ android:visible="false" />
+ <item
+ android:id="@+id/menu_settings"
+ android:title="@string/menu_settings"
+ android:showAsAction="never"
+ android:visible="false" />
+ </group>
</menu>
diff --git a/packages/DocumentsUI/res/values-af/strings.xml b/packages/DocumentsUI/res/values-af/strings.xml
index a3fdd78..1a7c620 100644
--- a/packages/DocumentsUI/res/values-af/strings.xml
+++ b/packages/DocumentsUI/res/values-af/strings.xml
@@ -111,6 +111,7 @@
<string name="rename_error" msgid="4203041674883412606">"Kon nie dokument hernoem nie"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Sommige lêers is omgeskakel"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"Gee <xliff:g id="APPNAME"><b>^1</b></xliff:g> toegang tot <xliff:g id="DIRECTORY"><i>^2</i></xliff:g>-gids op <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
+ <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Gee <xliff:g id="APPNAME"><b>^1</b></xliff:g> toegang tot <xliff:g id="DIRECTORY"><i>^2</i></xliff:g>-gids?"</string>
<string name="open_external_dialog_root_request" msgid="8899108702926347720">"Gee <xliff:g id="APPNAME"><b>^1</b></xliff:g> toegang tot jou data, insluitend foto\'s en video\'s, op <xliff:g id="STORAGE"><i>^2</i></xliff:g>?"</string>
<string name="never_ask_again" msgid="4295278542972859268">"Moenie weer vra nie"</string>
<string name="allow" msgid="7225948811296386551">"Laat toe"</string>
@@ -119,11 +120,18 @@
<item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> gekies</item>
<item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> gekies</item>
</plurals>
- <!-- no translation found for delete_filename_confirmation_message (5312817725577537488) -->
- <skip />
- <!-- no translation found for delete_foldername_confirmation_message (5885501832257285329) -->
- <skip />
- <!-- no translation found for delete_files_confirmation_message (8417505791395471802) -->
- <!-- no translation found for delete_folders_confirmation_message (9185648028213507769) -->
- <!-- no translation found for delete_items_confirmation_message (5376214433530243459) -->
+ <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"Vee \"<xliff:g id="NAME">%1$s</xliff:g>\" uit?"</string>
+ <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"Vee vouer \"<xliff:g id="NAME">%1$s</xliff:g>\" en sy inhoud uit?"</string>
+ <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+ <item quantity="other">Vee <xliff:g id="COUNT_1">%1$d</xliff:g> lêers uit?</item>
+ <item quantity="one">Vee <xliff:g id="COUNT_0">%1$d</xliff:g> lêer uit?</item>
+ </plurals>
+ <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+ <item quantity="other">Vee <xliff:g id="COUNT_1">%1$d</xliff:g> vouers en hul inhoud uit?</item>
+ <item quantity="one">Vee <xliff:g id="COUNT_0">%1$d</xliff:g> vouer en sy inhoud uit?</item>
+ </plurals>
+ <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+ <item quantity="other">Vee <xliff:g id="COUNT_1">%1$d</xliff:g> items uit?</item>
+ <item quantity="one">Vee <xliff:g id="COUNT_0">%1$d</xliff:g> item uit?</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-am/strings.xml b/packages/DocumentsUI/res/values-am/strings.xml
index df73bed..ca43dab 100644
--- a/packages/DocumentsUI/res/values-am/strings.xml
+++ b/packages/DocumentsUI/res/values-am/strings.xml
@@ -111,6 +111,7 @@
<string name="rename_error" msgid="4203041674883412606">"ሰነዱን ዳግም መሰየም አልተሳካም"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"አንዳንድ ፋይሎች ተለውጠዋል"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> በ<xliff:g id="STORAGE"><i>^3</i></xliff:g> ላይ የ<xliff:g id="DIRECTORY"><i>^2</i></xliff:g> ማውጫ መደረሻ ይሰጠው?"</string>
+ <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"የ<xliff:g id="DIRECTORY"><i>^2</i></xliff:g> ማውጫ መዳረሻ ለ<xliff:g id="APPNAME"><b>^1</b></xliff:g> ይሰጠው?"</string>
<string name="open_external_dialog_root_request" msgid="8899108702926347720">"በ<xliff:g id="STORAGE"><i>^2</i></xliff:g> ላይ ያሉትን ፎቶዎች እና ቪዲዮዎች ጨምሮ የውሂብዎ መዳረሻ ለ<xliff:g id="APPNAME"><b>^1</b></xliff:g> ይሰጥ?"</string>
<string name="never_ask_again" msgid="4295278542972859268">"ዳግም አትጠይቅ"</string>
<string name="allow" msgid="7225948811296386551">"ይፍቀዱ"</string>
@@ -119,11 +120,18 @@
<item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> ተመርጠዋል</item>
<item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ተመርጠዋል</item>
</plurals>
- <!-- no translation found for delete_filename_confirmation_message (5312817725577537488) -->
- <skip />
- <!-- no translation found for delete_foldername_confirmation_message (5885501832257285329) -->
- <skip />
- <!-- no translation found for delete_files_confirmation_message (8417505791395471802) -->
- <!-- no translation found for delete_folders_confirmation_message (9185648028213507769) -->
- <!-- no translation found for delete_items_confirmation_message (5376214433530243459) -->
+ <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"«<xliff:g id="NAME">%1$s</xliff:g>» ይሰረዝ?"</string>
+ <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"አቃፊ «<xliff:g id="NAME">%1$s</xliff:g>» እና ይዘቶቹ ይሰረዙ?"</string>
+ <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+ <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> ፋይሎች ይሰረዙ?</item>
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ፋይሎች ይሰረዙ?</item>
+ </plurals>
+ <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+ <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> አቃፊዎች እና ይዘቶቻቸው ይሰረዙ?</item>
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> አቃፊዎች እና ይዘቶቻቸው ይሰረዙ?</item>
+ </plurals>
+ <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+ <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> ንጥሎች ይሰረዙ?</item>
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ንጥሎች ይሰረዙ?</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-ar/strings.xml b/packages/DocumentsUI/res/values-ar/strings.xml
index d92eb5f..e6fac50 100644
--- a/packages/DocumentsUI/res/values-ar/strings.xml
+++ b/packages/DocumentsUI/res/values-ar/strings.xml
@@ -139,6 +139,7 @@
<string name="rename_error" msgid="4203041674883412606">"أخفقت إعادة تسمية المستند."</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"تم تحويل بعض الملفات"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"هل تريد منح التطبيق <xliff:g id="APPNAME"><b>^1</b></xliff:g> حق الوصول إلى الدليل <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> على <xliff:g id="STORAGE"><i>^3</i></xliff:g>؟"</string>
+ <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"هل تريد تمكين <xliff:g id="APPNAME"><b>^1</b></xliff:g> من الدخول إلى دليل <xliff:g id="DIRECTORY"><i>^2</i></xliff:g>؟"</string>
<string name="open_external_dialog_root_request" msgid="8899108702926347720">"هل تريد منح <xliff:g id="APPNAME"><b>^1</b></xliff:g> حق الوصول إلى بياناتك، بما في ذلك الصور ومقاطع الفيديو على <xliff:g id="STORAGE"><i>^2</i></xliff:g>؟"</string>
<string name="never_ask_again" msgid="4295278542972859268">"عدم السؤال مرة أخرى"</string>
<string name="allow" msgid="7225948811296386551">"السماح"</string>
@@ -153,7 +154,28 @@
</plurals>
<string name="delete_filename_confirmation_message" msgid="5312817725577537488">"هل تريد حذف \"<xliff:g id="NAME">%1$s</xliff:g>\"؟"</string>
<string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"هل تريد حذف المجلد \"<xliff:g id="NAME">%1$s</xliff:g>\" ومحتوياته؟"</string>
- <!-- no translation found for delete_files_confirmation_message (8417505791395471802) -->
- <!-- no translation found for delete_folders_confirmation_message (9185648028213507769) -->
- <!-- no translation found for delete_items_confirmation_message (5376214433530243459) -->
+ <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+ <item quantity="zero">هل تريد حذف <xliff:g id="COUNT_1">%1$d</xliff:g> ملف؟</item>
+ <item quantity="two">هل تريد حذف ملفين (<xliff:g id="COUNT_1">%1$d</xliff:g>)؟</item>
+ <item quantity="few">هل تريد حذف <xliff:g id="COUNT_1">%1$d</xliff:g> ملفات؟</item>
+ <item quantity="many">هل تريد حذف <xliff:g id="COUNT_1">%1$d</xliff:g> ملفًا؟</item>
+ <item quantity="other">هل تريد حذف <xliff:g id="COUNT_1">%1$d</xliff:g> ملف؟</item>
+ <item quantity="one">هل تريد حذف <xliff:g id="COUNT_0">%1$d</xliff:g> ملف؟</item>
+ </plurals>
+ <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+ <item quantity="zero">هل تريد حذف <xliff:g id="COUNT_1">%1$d</xliff:g> مجلد ومحتوياته؟</item>
+ <item quantity="two">هل تريد حذف مجلدين (<xliff:g id="COUNT_1">%1$d</xliff:g>) ومحتوياتهما؟</item>
+ <item quantity="few">هل تريد حذف <xliff:g id="COUNT_1">%1$d</xliff:g> مجلدات ومحتوياتها؟</item>
+ <item quantity="many">هل تريد حذف <xliff:g id="COUNT_1">%1$d</xliff:g> مجلدًا ومحتويات هذه المجلدات؟</item>
+ <item quantity="other">هل تريد حذف <xliff:g id="COUNT_1">%1$d</xliff:g> مجلد ومحتويات هذه المجلدات؟</item>
+ <item quantity="one">هل تريد حذف <xliff:g id="COUNT_0">%1$d</xliff:g> مجلد ومحتوياته؟</item>
+ </plurals>
+ <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+ <item quantity="zero">هل تريد حذف <xliff:g id="COUNT_1">%1$d</xliff:g> عنصر؟</item>
+ <item quantity="two">هل تريد حذف عنصرين (<xliff:g id="COUNT_1">%1$d</xliff:g>)؟</item>
+ <item quantity="few">هل تريد حذف <xliff:g id="COUNT_1">%1$d</xliff:g> عناصر؟</item>
+ <item quantity="many">هل تريد حذف <xliff:g id="COUNT_1">%1$d</xliff:g> عنصرًا؟</item>
+ <item quantity="other">هل تريد حذف <xliff:g id="COUNT_1">%1$d</xliff:g> عنصر؟</item>
+ <item quantity="one">هل تريد حذف <xliff:g id="COUNT_0">%1$d</xliff:g> عنصر؟</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-az-rAZ/strings.xml b/packages/DocumentsUI/res/values-az-rAZ/strings.xml
index 632fa6b..75a0686 100644
--- a/packages/DocumentsUI/res/values-az-rAZ/strings.xml
+++ b/packages/DocumentsUI/res/values-az-rAZ/strings.xml
@@ -111,6 +111,7 @@
<string name="rename_error" msgid="4203041674883412606">"Sənəd adını dəyişmək uğursuz oldu"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Bəzi fayllar konvertasiya edilib"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"<xliff:g id="STORAGE"><i>^3</i></xliff:g> yaddaşında <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> kataloquna <xliff:g id="APPNAME"><b>^1</b></xliff:g> girişi təqdim edilsin?"</string>
+ <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"<xliff:g id="DIRECTORY"><i>^2</i></xliff:g> kataloquna <xliff:g id="APPNAME"><b>^1</b></xliff:g> girişi təqdim edilsin?"</string>
<string name="open_external_dialog_root_request" msgid="8899108702926347720">"<xliff:g id="STORAGE"><i>^2</i></xliff:g> yaddaşında foto və videolar daxil olmaqla datanıza <xliff:g id="APPNAME"><b>^1</b></xliff:g> girişi təmin edilsin?"</string>
<string name="never_ask_again" msgid="4295278542972859268">"Bir daha soruşmayın"</string>
<string name="allow" msgid="7225948811296386551">"İcazə verin"</string>
@@ -119,11 +120,18 @@
<item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> seçilib</item>
<item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> seçilib</item>
</plurals>
- <!-- no translation found for delete_filename_confirmation_message (5312817725577537488) -->
- <skip />
- <!-- no translation found for delete_foldername_confirmation_message (5885501832257285329) -->
- <skip />
- <!-- no translation found for delete_files_confirmation_message (8417505791395471802) -->
- <!-- no translation found for delete_folders_confirmation_message (9185648028213507769) -->
- <!-- no translation found for delete_items_confirmation_message (5376214433530243459) -->
+ <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"\"<xliff:g id="NAME">%1$s</xliff:g>\" silinsin?"</string>
+ <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"\"<xliff:g id="NAME">%1$s</xliff:g>\" qovluğu və onun məzmunu silinsin?"</string>
+ <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+ <item quantity="other"> <xliff:g id="COUNT_1">%1$d</xliff:g> fayl silinsin?</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> fayl silinsin?</item>
+ </plurals>
+ <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> qovluq və onun məzmunu silinsin?</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> qovluq və onun məzmunu silinsin?</item>
+ </plurals>
+ <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> element silinsin?</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> element silinsin?</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-b+sr+Latn/strings.xml b/packages/DocumentsUI/res/values-b+sr+Latn/strings.xml
index 2d679ea..34c08bd 100644
--- a/packages/DocumentsUI/res/values-b+sr+Latn/strings.xml
+++ b/packages/DocumentsUI/res/values-b+sr+Latn/strings.xml
@@ -118,6 +118,7 @@
<string name="rename_error" msgid="4203041674883412606">"Preimenovanje dokumenta nije uspelo"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Neke datoteke su konvertovane"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"Želite li da aplikaciji <xliff:g id="APPNAME"><b>^1</b></xliff:g> odobrite pristup direktorijumu <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> na memorijskom prostoru <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
+ <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Želite da dozvolite da <xliff:g id="APPNAME"><b>^1</b></xliff:g> pristupa direktorijumu <xliff:g id="DIRECTORY"><i>^2</i></xliff:g>?"</string>
<string name="open_external_dialog_root_request" msgid="8899108702926347720">"Želite da li da dozvolite da aplikacija <xliff:g id="APPNAME"><b>^1</b></xliff:g> pristupa podacima, uključujući slike i video snimke, na lokaciji <xliff:g id="STORAGE"><i>^2</i></xliff:g>?"</string>
<string name="never_ask_again" msgid="4295278542972859268">"Ne pitaj ponovo"</string>
<string name="allow" msgid="7225948811296386551">"Dozvoli"</string>
@@ -129,7 +130,19 @@
</plurals>
<string name="delete_filename_confirmation_message" msgid="5312817725577537488">"Želite li da izbrišete „<xliff:g id="NAME">%1$s</xliff:g>“?"</string>
<string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"Želite li da izbrišete direktorijum „<xliff:g id="NAME">%1$s</xliff:g>“ i njegov sadržaj?"</string>
- <!-- no translation found for delete_files_confirmation_message (8417505791395471802) -->
- <!-- no translation found for delete_folders_confirmation_message (9185648028213507769) -->
- <!-- no translation found for delete_items_confirmation_message (5376214433530243459) -->
+ <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+ <item quantity="one">Želite li da izbrišete <xliff:g id="COUNT_1">%1$d</xliff:g> datoteku?</item>
+ <item quantity="few">Želite li da izbrišete <xliff:g id="COUNT_1">%1$d</xliff:g> datoteke?</item>
+ <item quantity="other">Želite li da izbrišete <xliff:g id="COUNT_1">%1$d</xliff:g> datoteka?</item>
+ </plurals>
+ <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+ <item quantity="one">Želite li da izbrišete <xliff:g id="COUNT_1">%1$d</xliff:g> direktorijum i njihov sadržaj?</item>
+ <item quantity="few">Želite li da izbrišete <xliff:g id="COUNT_1">%1$d</xliff:g> direktorijuma i njihov sadržaj?</item>
+ <item quantity="other">Želite li da izbrišete <xliff:g id="COUNT_1">%1$d</xliff:g> direktorijuma i njihov sadržaj?</item>
+ </plurals>
+ <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+ <item quantity="one">Želite li da izbrišete <xliff:g id="COUNT_1">%1$d</xliff:g> stavku?</item>
+ <item quantity="few">Želite li da izbrišete <xliff:g id="COUNT_1">%1$d</xliff:g> stavke?</item>
+ <item quantity="other">Želite li da izbrišete <xliff:g id="COUNT_1">%1$d</xliff:g> stavki?</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-be-rBY/strings.xml b/packages/DocumentsUI/res/values-be-rBY/strings.xml
index abd4679..8493c477 100644
--- a/packages/DocumentsUI/res/values-be-rBY/strings.xml
+++ b/packages/DocumentsUI/res/values-be-rBY/strings.xml
@@ -125,6 +125,7 @@
<string name="rename_error" msgid="4203041674883412606">"Не атрымалася перайменаваць дакумент"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Некаторыя файлы былі сканвертаваныя"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"Даць праграме <xliff:g id="APPNAME"><b>^1</b></xliff:g> доступ да дырэкторыі <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> у <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
+ <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Даць праграме <xliff:g id="APPNAME"><b>^1</b></xliff:g> доступ да дырэкторыі <xliff:g id="DIRECTORY"><i>^2</i></xliff:g>?"</string>
<string name="open_external_dialog_root_request" msgid="8899108702926347720">"Даць <xliff:g id="APPNAME"><b>^1</b></xliff:g> доступ да вашых даных, у тым ліку фатаграфій і відэа, на <xliff:g id="STORAGE"><i>^2</i></xliff:g>?"</string>
<string name="never_ask_again" msgid="4295278542972859268">"Больш не пытацца"</string>
<string name="allow" msgid="7225948811296386551">"Дазволіць"</string>
@@ -135,11 +136,24 @@
<item quantity="many">Выбрана <xliff:g id="COUNT_1">%1$d</xliff:g></item>
<item quantity="other">Выбрана <xliff:g id="COUNT_1">%1$d</xliff:g></item>
</plurals>
- <!-- no translation found for delete_filename_confirmation_message (5312817725577537488) -->
- <skip />
- <!-- no translation found for delete_foldername_confirmation_message (5885501832257285329) -->
- <skip />
- <!-- no translation found for delete_files_confirmation_message (8417505791395471802) -->
- <!-- no translation found for delete_folders_confirmation_message (9185648028213507769) -->
- <!-- no translation found for delete_items_confirmation_message (5376214433530243459) -->
+ <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"Выдаліць \"<xliff:g id="NAME">%1$s</xliff:g>\"?"</string>
+ <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"Выдаліць папку \"<xliff:g id="NAME">%1$s</xliff:g>\" і яе змесціва?"</string>
+ <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+ <item quantity="one">Выдаліць <xliff:g id="COUNT_1">%1$d</xliff:g> файл?</item>
+ <item quantity="few">Выдаліць <xliff:g id="COUNT_1">%1$d</xliff:g> файлы?</item>
+ <item quantity="many">Выдаліць <xliff:g id="COUNT_1">%1$d</xliff:g> файлаў?</item>
+ <item quantity="other">Выдаліць <xliff:g id="COUNT_1">%1$d</xliff:g> файла?</item>
+ </plurals>
+ <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+ <item quantity="one">Выдаліць <xliff:g id="COUNT_1">%1$d</xliff:g> папку і іх змесціва?</item>
+ <item quantity="few">Выдаліць <xliff:g id="COUNT_1">%1$d</xliff:g> папкі і іх змесціва?</item>
+ <item quantity="many">Выдаліць <xliff:g id="COUNT_1">%1$d</xliff:g> папак і іх змесціва?</item>
+ <item quantity="other">Выдаліць <xliff:g id="COUNT_1">%1$d</xliff:g> папкі і іх змесціва?</item>
+ </plurals>
+ <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+ <item quantity="one">Выдаліць <xliff:g id="COUNT_1">%1$d</xliff:g> элемент?</item>
+ <item quantity="few">Выдаліць <xliff:g id="COUNT_1">%1$d</xliff:g> элементы?</item>
+ <item quantity="many">Выдаліць <xliff:g id="COUNT_1">%1$d</xliff:g> элементаў?</item>
+ <item quantity="other">Выдаліць <xliff:g id="COUNT_1">%1$d</xliff:g> элемента?</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-bg/strings.xml b/packages/DocumentsUI/res/values-bg/strings.xml
index 4822adb..1914bf5 100644
--- a/packages/DocumentsUI/res/values-bg/strings.xml
+++ b/packages/DocumentsUI/res/values-bg/strings.xml
@@ -111,6 +111,7 @@
<string name="rename_error" msgid="4203041674883412606">"Преименуването на документа не бе успешно"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Някои файлове бяха преобразувани"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"Да се предостави ли на <xliff:g id="APPNAME"><b>^1</b></xliff:g> достъп до директорията „<xliff:g id="DIRECTORY"><i>^2</i></xliff:g>“ в/ъв <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
+ <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Да се предостави ли на <xliff:g id="APPNAME"><b>^1</b></xliff:g> достъп до директорията „<xliff:g id="DIRECTORY"><i>^2</i></xliff:g>“?"</string>
<string name="open_external_dialog_root_request" msgid="8899108702926347720">"Да се предостави ли на <xliff:g id="APPNAME"><b>^1</b></xliff:g> достъп до данните ви в хранилището (<xliff:g id="STORAGE"><i>^2</i></xliff:g>), включително снимки и видеоклипове?"</string>
<string name="never_ask_again" msgid="4295278542972859268">"Без повторно питане"</string>
<string name="allow" msgid="7225948811296386551">"Разрешаване"</string>
@@ -121,7 +122,16 @@
</plurals>
<string name="delete_filename_confirmation_message" msgid="5312817725577537488">"Искате ли да изтриете „<xliff:g id="NAME">%1$s</xliff:g>“?"</string>
<string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"Искате ли да изтриете папката „<xliff:g id="NAME">%1$s</xliff:g>“ и съдържанието в нея?"</string>
- <!-- no translation found for delete_files_confirmation_message (8417505791395471802) -->
- <!-- no translation found for delete_folders_confirmation_message (9185648028213507769) -->
- <!-- no translation found for delete_items_confirmation_message (5376214433530243459) -->
+ <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+ <item quantity="other">Искате ли да изтриете <xliff:g id="COUNT_1">%1$d</xliff:g> файла?</item>
+ <item quantity="one">Искате ли да изтриете <xliff:g id="COUNT_0">%1$d</xliff:g> файл?</item>
+ </plurals>
+ <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+ <item quantity="other">Искате ли да изтриете <xliff:g id="COUNT_1">%1$d</xliff:g> папки и съдържанието в тях?</item>
+ <item quantity="one">Искате ли да изтриете <xliff:g id="COUNT_0">%1$d</xliff:g> папка и съдържанието в нея?</item>
+ </plurals>
+ <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+ <item quantity="other">Искате ли да изтриете <xliff:g id="COUNT_1">%1$d</xliff:g> елемента?</item>
+ <item quantity="one">Искате ли да изтриете <xliff:g id="COUNT_0">%1$d</xliff:g> елемент?</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-bn-rBD/strings.xml b/packages/DocumentsUI/res/values-bn-rBD/strings.xml
index 5709692..d931c2b 100644
--- a/packages/DocumentsUI/res/values-bn-rBD/strings.xml
+++ b/packages/DocumentsUI/res/values-bn-rBD/strings.xml
@@ -111,6 +111,7 @@
<string name="rename_error" msgid="4203041674883412606">"দস্তাবেজের পুনঃনামকরণ ব্যর্থ হয়েছে৷"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"কিছু ফাইল রূপান্তরিত হয়েছে"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> কে <xliff:g id="STORAGE"><i>^3</i></xliff:g> এ <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> সংগ্রহ অ্যাক্সেস করার মঞ্জুরি দিতে চান?"</string>
+ <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> কে <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> সংগ্রহ অ্যাক্সেস করার অনুমতি দেবেন?"</string>
<string name="open_external_dialog_root_request" msgid="8899108702926347720">"<xliff:g id="STORAGE"><i>^2</i></xliff:g> এ থাকা ফটো ও ভিডিওগুলি সমেত <xliff:g id="APPNAME"><b>^1</b></xliff:g> কে আপনার ডেটা অ্যাক্সেস করার অনুমতি দেবেন?"</string>
<string name="never_ask_again" msgid="4295278542972859268">"আর জিজ্ঞাসা করবেন না"</string>
<string name="allow" msgid="7225948811296386551">"অনুমতি দিন"</string>
@@ -121,7 +122,16 @@
</plurals>
<string name="delete_filename_confirmation_message" msgid="5312817725577537488">"\"<xliff:g id="NAME">%1$s</xliff:g>\" মুছবেন?"</string>
<string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"\"<xliff:g id="NAME">%1$s</xliff:g>\" ফোল্ডার এবং এটির সামগ্রীগুলিকে মুছবেন?"</string>
- <!-- no translation found for delete_files_confirmation_message (8417505791395471802) -->
- <!-- no translation found for delete_folders_confirmation_message (9185648028213507769) -->
- <!-- no translation found for delete_items_confirmation_message (5376214433530243459) -->
+ <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+ <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g>টি ফাইল মুছবেন?</item>
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g>টি ফাইল মুছবেন?</item>
+ </plurals>
+ <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+ <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g>টি ফোল্ডার এবং সেগুলির সামগ্রী মুছবেন?</item>
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g>টি ফোল্ডার এবং সেগুলির সামগ্রী মুছবেন?</item>
+ </plurals>
+ <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+ <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g>টি আইটেম মুছবেন?</item>
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g>টি আইটেম মুছবেন?</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-bs-rBA/strings.xml b/packages/DocumentsUI/res/values-bs-rBA/strings.xml
index 9c94a05..47ff436 100644
--- a/packages/DocumentsUI/res/values-bs-rBA/strings.xml
+++ b/packages/DocumentsUI/res/values-bs-rBA/strings.xml
@@ -118,6 +118,7 @@
<string name="rename_error" msgid="4203041674883412606">"Nije uspjelo preimenovanje dokumenta"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Neke od datoteka su pretvorene"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"Omogućiti <xliff:g id="APPNAME"><b>^1</b></xliff:g> pristup direktoriju <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> sa <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
+ <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Odobriti aplikaciji <xliff:g id="APPNAME"><b>^1</b></xliff:g> pristup direktoriju <xliff:g id="DIRECTORY"><i>^2</i></xliff:g>?"</string>
<string name="open_external_dialog_root_request" msgid="8899108702926347720">"Želite li odobriti aplikaciji <xliff:g id="APPNAME"><b>^1</b></xliff:g> pristup svojim podacima, uključujući fotografije i video zapise, na <xliff:g id="STORAGE"><i>^2</i></xliff:g> ?"</string>
<string name="never_ask_again" msgid="4295278542972859268">"Ne pitaj ponovo"</string>
<string name="allow" msgid="7225948811296386551">"Dozvoli"</string>
@@ -127,11 +128,21 @@
<item quantity="few"><xliff:g id="COUNT_1">%1$d</xliff:g> stavke su odabrane</item>
<item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> stavki je odabrano</item>
</plurals>
- <!-- no translation found for delete_filename_confirmation_message (5312817725577537488) -->
- <skip />
- <!-- no translation found for delete_foldername_confirmation_message (5885501832257285329) -->
- <skip />
- <!-- no translation found for delete_files_confirmation_message (8417505791395471802) -->
- <!-- no translation found for delete_folders_confirmation_message (9185648028213507769) -->
- <!-- no translation found for delete_items_confirmation_message (5376214433530243459) -->
+ <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"Želite li izbrisati \"<xliff:g id="NAME">%1$s</xliff:g>\"?"</string>
+ <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"Želite li izbrisati folder \"<xliff:g id="NAME">%1$s</xliff:g>\" i njegov sadržaj?"</string>
+ <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+ <item quantity="one">Želite li izbrisati <xliff:g id="COUNT_1">%1$d</xliff:g> fajl?</item>
+ <item quantity="few">Želite li izbrisati <xliff:g id="COUNT_1">%1$d</xliff:g> fajla?</item>
+ <item quantity="other">Želite li izbrisati <xliff:g id="COUNT_1">%1$d</xliff:g> fajlova?</item>
+ </plurals>
+ <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+ <item quantity="one">Želite li izbrisati <xliff:g id="COUNT_1">%1$d</xliff:g> folder i njihov sadržaj?</item>
+ <item quantity="few">Želite li izbrisati <xliff:g id="COUNT_1">%1$d</xliff:g> foldera i njihov sadržaj?</item>
+ <item quantity="other">Želite li izbrisati <xliff:g id="COUNT_1">%1$d</xliff:g> foldera i njihov sadržaj?</item>
+ </plurals>
+ <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+ <item quantity="one">Želite li izbrisati <xliff:g id="COUNT_1">%1$d</xliff:g> stavku?</item>
+ <item quantity="few">Želite li izbrisati <xliff:g id="COUNT_1">%1$d</xliff:g> stavke?</item>
+ <item quantity="other">Želite li izbrisati <xliff:g id="COUNT_1">%1$d</xliff:g> stavki?</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-ca/strings.xml b/packages/DocumentsUI/res/values-ca/strings.xml
index 4ecec9f..09af97d 100644
--- a/packages/DocumentsUI/res/values-ca/strings.xml
+++ b/packages/DocumentsUI/res/values-ca/strings.xml
@@ -111,7 +111,8 @@
<string name="rename_error" msgid="4203041674883412606">"No s\'ha pogut canviar el nom del document"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"S\'han convertit alguns fitxers"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"Vols que l\'aplicació <xliff:g id="APPNAME"><b>^1</b></xliff:g> tingui accés al directori <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> de l\'emmagatzematge <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
- <string name="open_external_dialog_root_request" msgid="8899108702926347720">"Vols que l\'aplicació <xliff:g id="APPNAME"><b>^1</b></xliff:g> tingui accés a les dades de l\'emmagatzematge <xliff:g id="STORAGE"><i>^2</i></xliff:g>, incloses les fotos i els vídeos?"</string>
+ <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Vols que l\'aplicació <xliff:g id="APPNAME"><b>^1</b></xliff:g> tingui accés al directori <xliff:g id="DIRECTORY"><i>^2</i></xliff:g>?"</string>
+ <string name="open_external_dialog_root_request" msgid="8899108702926347720">"Vols que l\'aplicació <xliff:g id="APPNAME"><b>^1</b></xliff:g> tingui accés a les dades de <xliff:g id="STORAGE"><i>^2</i></xliff:g>, incloses les fotos i els vídeos?"</string>
<string name="never_ask_again" msgid="4295278542972859268">"No m\'ho demanis més"</string>
<string name="allow" msgid="7225948811296386551">"Permet"</string>
<string name="deny" msgid="2081879885755434506">"Denega"</string>
@@ -121,7 +122,16 @@
</plurals>
<string name="delete_filename_confirmation_message" msgid="5312817725577537488">"Vols suprimir el fitxer <xliff:g id="NAME">%1$s</xliff:g>?"</string>
<string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"Vols suprimir la carpeta <xliff:g id="NAME">%1$s</xliff:g> i el seu contingut?"</string>
- <!-- no translation found for delete_files_confirmation_message (8417505791395471802) -->
- <!-- no translation found for delete_folders_confirmation_message (9185648028213507769) -->
- <!-- no translation found for delete_items_confirmation_message (5376214433530243459) -->
+ <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+ <item quantity="other">Vols suprimir <xliff:g id="COUNT_1">%1$d</xliff:g> fitxers?</item>
+ <item quantity="one">Vols suprimir <xliff:g id="COUNT_0">%1$d</xliff:g> fitxer?</item>
+ </plurals>
+ <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+ <item quantity="other">Vols suprimir <xliff:g id="COUNT_1">%1$d</xliff:g> carpetes i el seu contingut?</item>
+ <item quantity="one">Vols suprimir <xliff:g id="COUNT_0">%1$d</xliff:g> carpeta i el seu contingut?</item>
+ </plurals>
+ <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+ <item quantity="other">Vols suprimir <xliff:g id="COUNT_1">%1$d</xliff:g> elements?</item>
+ <item quantity="one">Vols suprimir <xliff:g id="COUNT_0">%1$d</xliff:g> element?</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-cs/strings.xml b/packages/DocumentsUI/res/values-cs/strings.xml
index 3c6e81d..cba2e0e 100644
--- a/packages/DocumentsUI/res/values-cs/strings.xml
+++ b/packages/DocumentsUI/res/values-cs/strings.xml
@@ -125,6 +125,7 @@
<string name="rename_error" msgid="4203041674883412606">"Dokument se nepodařilo přejmenovat."</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Některé soubory byly převedeny"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"Chcete aplikaci <xliff:g id="APPNAME"><b>^1</b></xliff:g> udělit přístup k adresáři <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> v úložišti <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
+ <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Chcete aplikaci <xliff:g id="APPNAME"><b>^1</b></xliff:g> udělit přístup k adresáři <xliff:g id="DIRECTORY"><i>^2</i></xliff:g>?"</string>
<string name="open_external_dialog_root_request" msgid="8899108702926347720">"Chcete aplikaci <xliff:g id="APPNAME"><b>^1</b></xliff:g> udělit přístup ke svým datům v úložišti <xliff:g id="STORAGE"><i>^2</i></xliff:g>, včetně fotek a videí?"</string>
<string name="never_ask_again" msgid="4295278542972859268">"Příště se neptat"</string>
<string name="allow" msgid="7225948811296386551">"Povolit"</string>
@@ -137,7 +138,22 @@
</plurals>
<string name="delete_filename_confirmation_message" msgid="5312817725577537488">"Smazat soubor <xliff:g id="NAME">%1$s</xliff:g>?"</string>
<string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"Smazat složku <xliff:g id="NAME">%1$s</xliff:g> a její obsah?"</string>
- <!-- no translation found for delete_files_confirmation_message (8417505791395471802) -->
- <!-- no translation found for delete_folders_confirmation_message (9185648028213507769) -->
- <!-- no translation found for delete_items_confirmation_message (5376214433530243459) -->
+ <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+ <item quantity="few">Smazat <xliff:g id="COUNT_1">%1$d</xliff:g> soubory?</item>
+ <item quantity="many">Smazat <xliff:g id="COUNT_1">%1$d</xliff:g> souboru?</item>
+ <item quantity="other">Smazat <xliff:g id="COUNT_1">%1$d</xliff:g> souborů?</item>
+ <item quantity="one">Smazat <xliff:g id="COUNT_0">%1$d</xliff:g> soubor?</item>
+ </plurals>
+ <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+ <item quantity="few">Smazat <xliff:g id="COUNT_1">%1$d</xliff:g> složky a jejich obsah?</item>
+ <item quantity="many">Smazat <xliff:g id="COUNT_1">%1$d</xliff:g> složky a jejich obsah?</item>
+ <item quantity="other">Smazat <xliff:g id="COUNT_1">%1$d</xliff:g> složek a jejich obsah?</item>
+ <item quantity="one">Smazat <xliff:g id="COUNT_0">%1$d</xliff:g> složku a její obsah?</item>
+ </plurals>
+ <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+ <item quantity="few">Smazat <xliff:g id="COUNT_1">%1$d</xliff:g> položky?</item>
+ <item quantity="many">Smazat <xliff:g id="COUNT_1">%1$d</xliff:g> položky?</item>
+ <item quantity="other">Smazat <xliff:g id="COUNT_1">%1$d</xliff:g> položek?</item>
+ <item quantity="one">Smazat <xliff:g id="COUNT_0">%1$d</xliff:g> položku?</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-da/strings.xml b/packages/DocumentsUI/res/values-da/strings.xml
index 679506b..f048e34 100644
--- a/packages/DocumentsUI/res/values-da/strings.xml
+++ b/packages/DocumentsUI/res/values-da/strings.xml
@@ -111,6 +111,7 @@
<string name="rename_error" msgid="4203041674883412606">"Dokumentet kunne ikke omdøbes"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Nogle filer er konverteret"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"Vil du give <xliff:g id="APPNAME"><b>^1</b></xliff:g> adgang til mappen <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> på <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
+ <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Vil du give <xliff:g id="APPNAME"><b>^1</b></xliff:g> adgang til indekset <xliff:g id="DIRECTORY"><i>^2</i></xliff:g>?"</string>
<string name="open_external_dialog_root_request" msgid="8899108702926347720">"Vil du give <xliff:g id="APPNAME"><b>^1</b></xliff:g> adgang til dine data, herunder billeder og videoer på <xliff:g id="STORAGE"><i>^2</i></xliff:g>?"</string>
<string name="never_ask_again" msgid="4295278542972859268">"Spørg ikke igen"</string>
<string name="allow" msgid="7225948811296386551">"Tillad"</string>
@@ -121,7 +122,16 @@
</plurals>
<string name="delete_filename_confirmation_message" msgid="5312817725577537488">"Vil du slette \"<xliff:g id="NAME">%1$s</xliff:g>\"?"</string>
<string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"Vil du slette mappen \"<xliff:g id="NAME">%1$s</xliff:g>\" og dens indhold?"</string>
- <!-- no translation found for delete_files_confirmation_message (8417505791395471802) -->
- <!-- no translation found for delete_folders_confirmation_message (9185648028213507769) -->
- <!-- no translation found for delete_items_confirmation_message (5376214433530243459) -->
+ <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+ <item quantity="one">Vil du slette <xliff:g id="COUNT_1">%1$d</xliff:g> fil?</item>
+ <item quantity="other">Vil du slette <xliff:g id="COUNT_1">%1$d</xliff:g> filer?</item>
+ </plurals>
+ <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+ <item quantity="one">Vil du slette <xliff:g id="COUNT_1">%1$d</xliff:g> mappe og dens indhold?</item>
+ <item quantity="other">Vil du slette <xliff:g id="COUNT_1">%1$d</xliff:g> mapper og deres indhold?</item>
+ </plurals>
+ <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+ <item quantity="one">Vil du slette <xliff:g id="COUNT_1">%1$d</xliff:g> element?</item>
+ <item quantity="other">Vil du slette <xliff:g id="COUNT_1">%1$d</xliff:g> elementer?</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-de/strings.xml b/packages/DocumentsUI/res/values-de/strings.xml
index b48afb0..a6eae70 100644
--- a/packages/DocumentsUI/res/values-de/strings.xml
+++ b/packages/DocumentsUI/res/values-de/strings.xml
@@ -111,6 +111,7 @@
<string name="rename_error" msgid="4203041674883412606">"Dokument konnte nicht umbenannt werden"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Einige Dateien wurden konvertiert"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> Zugriff auf das Verzeichnis <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> auf <xliff:g id="STORAGE"><i>^3</i></xliff:g> geben?"</string>
+ <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Möchtest du <xliff:g id="APPNAME"><b>^1</b></xliff:g> Zugriff auf das Verzeichnis <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> geben?"</string>
<string name="open_external_dialog_root_request" msgid="8899108702926347720">"Möchtest du <xliff:g id="APPNAME"><b>^1</b></xliff:g> Zugriff auf deine Daten auf <xliff:g id="STORAGE"><i>^2</i></xliff:g> geben, einschließlich Fotos und Videos?"</string>
<string name="never_ask_again" msgid="4295278542972859268">"Nicht mehr fragen"</string>
<string name="allow" msgid="7225948811296386551">"Zulassen"</string>
@@ -121,7 +122,16 @@
</plurals>
<string name="delete_filename_confirmation_message" msgid="5312817725577537488">"\"<xliff:g id="NAME">%1$s</xliff:g>\" löschen?"</string>
<string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"Ordner \"<xliff:g id="NAME">%1$s</xliff:g>\" und dessen Inhalte löschen?"</string>
- <!-- no translation found for delete_files_confirmation_message (8417505791395471802) -->
- <!-- no translation found for delete_folders_confirmation_message (9185648028213507769) -->
- <!-- no translation found for delete_items_confirmation_message (5376214433530243459) -->
+ <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+ <item quantity="other">Möchtest du <xliff:g id="COUNT_1">%1$d</xliff:g> Dateien löschen?</item>
+ <item quantity="one">Möchtest du <xliff:g id="COUNT_0">%1$d</xliff:g> Datei löschen?</item>
+ </plurals>
+ <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+ <item quantity="other">Möchtest du <xliff:g id="COUNT_1">%1$d</xliff:g> Ordner und deren Inhalte löschen?</item>
+ <item quantity="one">Möchtest du <xliff:g id="COUNT_0">%1$d</xliff:g> Ordner und dessen Inhalte löschen?</item>
+ </plurals>
+ <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+ <item quantity="other">Möchtest du <xliff:g id="COUNT_1">%1$d</xliff:g> Elemente löschen?</item>
+ <item quantity="one">Möchtest du <xliff:g id="COUNT_0">%1$d</xliff:g> Element löschen?</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-el/strings.xml b/packages/DocumentsUI/res/values-el/strings.xml
index 3872c40..7dc2067 100644
--- a/packages/DocumentsUI/res/values-el/strings.xml
+++ b/packages/DocumentsUI/res/values-el/strings.xml
@@ -111,6 +111,7 @@
<string name="rename_error" msgid="4203041674883412606">"Αποτυχία μετονομασίας εγγράφου"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Ορισμένα αρχεία μετατράπηκαν"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"Να εκχωρηθεί στην εφαρμογή <xliff:g id="APPNAME"><b>^1</b></xliff:g> πρόσβαση στον κατάλογο <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> στον αποθηκευτικό χώρο <xliff:g id="STORAGE"><i>^3</i></xliff:g>;"</string>
+ <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Εκχώρηση πρόσβασης στην εφαρμογή <xliff:g id="APPNAME"><b>^1</b></xliff:g> στον κατάλογο <xliff:g id="DIRECTORY"><i>^2</i></xliff:g>;"</string>
<string name="open_external_dialog_root_request" msgid="8899108702926347720">"Θέλετε να εκχωρήσετε πρόσβαση στα δεδομένα σας στην εφαρμογή <xliff:g id="APPNAME"><b>^1</b></xliff:g>, συμπεριλαμβανομένων των φωτογραφιών και των βίντεό σας, στον αποθηκευτικό χώρο <xliff:g id="STORAGE"><i>^2</i></xliff:g>;"</string>
<string name="never_ask_again" msgid="4295278542972859268">"Να μην ερωτηθώ ξανά"</string>
<string name="allow" msgid="7225948811296386551">"Να επιτρέπεται"</string>
@@ -121,7 +122,16 @@
</plurals>
<string name="delete_filename_confirmation_message" msgid="5312817725577537488">"Να διαγραφεί το αρχείο \"<xliff:g id="NAME">%1$s</xliff:g>\";"</string>
<string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"Να διαγραφεί ο φάκελος \"<xliff:g id="NAME">%1$s</xliff:g>\" και τα περιεχόμενά του;"</string>
- <!-- no translation found for delete_files_confirmation_message (8417505791395471802) -->
- <!-- no translation found for delete_folders_confirmation_message (9185648028213507769) -->
- <!-- no translation found for delete_items_confirmation_message (5376214433530243459) -->
+ <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+ <item quantity="other">Να διαγραφούν <xliff:g id="COUNT_1">%1$d</xliff:g> αρχεία;</item>
+ <item quantity="one">Να διαγραφεί <xliff:g id="COUNT_0">%1$d</xliff:g> αρχείο;</item>
+ </plurals>
+ <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+ <item quantity="other">Να διαγραφούν <xliff:g id="COUNT_1">%1$d</xliff:g> φάκελοι και τα περιεχόμενά τους;</item>
+ <item quantity="one">Να διαγραφεί <xliff:g id="COUNT_0">%1$d</xliff:g> φάκελος και τα περιεχόμενά του;</item>
+ </plurals>
+ <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+ <item quantity="other">Να διαγραφούν <xliff:g id="COUNT_1">%1$d</xliff:g> στοιχεία;</item>
+ <item quantity="one">Να διαγραφεί <xliff:g id="COUNT_0">%1$d</xliff:g> στοιχείο;</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-en-rAU/strings.xml b/packages/DocumentsUI/res/values-en-rAU/strings.xml
index 8a56f6c..8524de5 100644
--- a/packages/DocumentsUI/res/values-en-rAU/strings.xml
+++ b/packages/DocumentsUI/res/values-en-rAU/strings.xml
@@ -111,6 +111,7 @@
<string name="rename_error" msgid="4203041674883412606">"Failed to rename document"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Some files were converted"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"Grant <xliff:g id="APPNAME"><b>^1</b></xliff:g> access to <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> directory on <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
+ <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Grant <xliff:g id="APPNAME"><b>^1</b></xliff:g> access to <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> directory?"</string>
<string name="open_external_dialog_root_request" msgid="8899108702926347720">"Grant <xliff:g id="APPNAME"><b>^1</b></xliff:g> access to your data, including photos and videos, on <xliff:g id="STORAGE"><i>^2</i></xliff:g>?"</string>
<string name="never_ask_again" msgid="4295278542972859268">"Don\'t ask again"</string>
<string name="allow" msgid="7225948811296386551">"Allow"</string>
@@ -121,7 +122,16 @@
</plurals>
<string name="delete_filename_confirmation_message" msgid="5312817725577537488">"Delete \"<xliff:g id="NAME">%1$s</xliff:g>\"?"</string>
<string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"Delete folder \"<xliff:g id="NAME">%1$s</xliff:g>\" and its contents?"</string>
- <!-- no translation found for delete_files_confirmation_message (8417505791395471802) -->
- <!-- no translation found for delete_folders_confirmation_message (9185648028213507769) -->
- <!-- no translation found for delete_items_confirmation_message (5376214433530243459) -->
+ <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+ <item quantity="other">Delete <xliff:g id="COUNT_1">%1$d</xliff:g> files?</item>
+ <item quantity="one">Delete <xliff:g id="COUNT_0">%1$d</xliff:g> file?</item>
+ </plurals>
+ <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+ <item quantity="other">Delete <xliff:g id="COUNT_1">%1$d</xliff:g> folders and their contents?</item>
+ <item quantity="one">Delete <xliff:g id="COUNT_0">%1$d</xliff:g> folder and its contents?</item>
+ </plurals>
+ <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+ <item quantity="other">Delete <xliff:g id="COUNT_1">%1$d</xliff:g> items?</item>
+ <item quantity="one">Delete <xliff:g id="COUNT_0">%1$d</xliff:g> item?</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-en-rGB/strings.xml b/packages/DocumentsUI/res/values-en-rGB/strings.xml
index 8a56f6c..8524de5 100644
--- a/packages/DocumentsUI/res/values-en-rGB/strings.xml
+++ b/packages/DocumentsUI/res/values-en-rGB/strings.xml
@@ -111,6 +111,7 @@
<string name="rename_error" msgid="4203041674883412606">"Failed to rename document"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Some files were converted"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"Grant <xliff:g id="APPNAME"><b>^1</b></xliff:g> access to <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> directory on <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
+ <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Grant <xliff:g id="APPNAME"><b>^1</b></xliff:g> access to <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> directory?"</string>
<string name="open_external_dialog_root_request" msgid="8899108702926347720">"Grant <xliff:g id="APPNAME"><b>^1</b></xliff:g> access to your data, including photos and videos, on <xliff:g id="STORAGE"><i>^2</i></xliff:g>?"</string>
<string name="never_ask_again" msgid="4295278542972859268">"Don\'t ask again"</string>
<string name="allow" msgid="7225948811296386551">"Allow"</string>
@@ -121,7 +122,16 @@
</plurals>
<string name="delete_filename_confirmation_message" msgid="5312817725577537488">"Delete \"<xliff:g id="NAME">%1$s</xliff:g>\"?"</string>
<string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"Delete folder \"<xliff:g id="NAME">%1$s</xliff:g>\" and its contents?"</string>
- <!-- no translation found for delete_files_confirmation_message (8417505791395471802) -->
- <!-- no translation found for delete_folders_confirmation_message (9185648028213507769) -->
- <!-- no translation found for delete_items_confirmation_message (5376214433530243459) -->
+ <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+ <item quantity="other">Delete <xliff:g id="COUNT_1">%1$d</xliff:g> files?</item>
+ <item quantity="one">Delete <xliff:g id="COUNT_0">%1$d</xliff:g> file?</item>
+ </plurals>
+ <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+ <item quantity="other">Delete <xliff:g id="COUNT_1">%1$d</xliff:g> folders and their contents?</item>
+ <item quantity="one">Delete <xliff:g id="COUNT_0">%1$d</xliff:g> folder and its contents?</item>
+ </plurals>
+ <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+ <item quantity="other">Delete <xliff:g id="COUNT_1">%1$d</xliff:g> items?</item>
+ <item quantity="one">Delete <xliff:g id="COUNT_0">%1$d</xliff:g> item?</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-en-rIN/strings.xml b/packages/DocumentsUI/res/values-en-rIN/strings.xml
index 8a56f6c..8524de5 100644
--- a/packages/DocumentsUI/res/values-en-rIN/strings.xml
+++ b/packages/DocumentsUI/res/values-en-rIN/strings.xml
@@ -111,6 +111,7 @@
<string name="rename_error" msgid="4203041674883412606">"Failed to rename document"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Some files were converted"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"Grant <xliff:g id="APPNAME"><b>^1</b></xliff:g> access to <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> directory on <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
+ <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Grant <xliff:g id="APPNAME"><b>^1</b></xliff:g> access to <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> directory?"</string>
<string name="open_external_dialog_root_request" msgid="8899108702926347720">"Grant <xliff:g id="APPNAME"><b>^1</b></xliff:g> access to your data, including photos and videos, on <xliff:g id="STORAGE"><i>^2</i></xliff:g>?"</string>
<string name="never_ask_again" msgid="4295278542972859268">"Don\'t ask again"</string>
<string name="allow" msgid="7225948811296386551">"Allow"</string>
@@ -121,7 +122,16 @@
</plurals>
<string name="delete_filename_confirmation_message" msgid="5312817725577537488">"Delete \"<xliff:g id="NAME">%1$s</xliff:g>\"?"</string>
<string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"Delete folder \"<xliff:g id="NAME">%1$s</xliff:g>\" and its contents?"</string>
- <!-- no translation found for delete_files_confirmation_message (8417505791395471802) -->
- <!-- no translation found for delete_folders_confirmation_message (9185648028213507769) -->
- <!-- no translation found for delete_items_confirmation_message (5376214433530243459) -->
+ <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+ <item quantity="other">Delete <xliff:g id="COUNT_1">%1$d</xliff:g> files?</item>
+ <item quantity="one">Delete <xliff:g id="COUNT_0">%1$d</xliff:g> file?</item>
+ </plurals>
+ <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+ <item quantity="other">Delete <xliff:g id="COUNT_1">%1$d</xliff:g> folders and their contents?</item>
+ <item quantity="one">Delete <xliff:g id="COUNT_0">%1$d</xliff:g> folder and its contents?</item>
+ </plurals>
+ <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+ <item quantity="other">Delete <xliff:g id="COUNT_1">%1$d</xliff:g> items?</item>
+ <item quantity="one">Delete <xliff:g id="COUNT_0">%1$d</xliff:g> item?</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-es-rUS/strings.xml b/packages/DocumentsUI/res/values-es-rUS/strings.xml
index 3f36f41..87641a7 100644
--- a/packages/DocumentsUI/res/values-es-rUS/strings.xml
+++ b/packages/DocumentsUI/res/values-es-rUS/strings.xml
@@ -111,6 +111,7 @@
<string name="rename_error" msgid="4203041674883412606">"No se pudo cambiar el nombre del documento"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Se convirtieron algunos archivos"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"¿Otorgar acceso a <xliff:g id="APPNAME"><b>^1</b></xliff:g> al directorio <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> en <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
+ <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"¿Quieres otorgar acceso a <xliff:g id="APPNAME"><b>^1</b></xliff:g> al directorio <xliff:g id="DIRECTORY"><i>^2</i></xliff:g>?"</string>
<string name="open_external_dialog_root_request" msgid="8899108702926347720">"¿Quieres otorgar acceso a la app de <xliff:g id="APPNAME"><b>^1</b></xliff:g> a tus datos, incluidas tus fotos y videos en <xliff:g id="STORAGE"><i>^2</i></xliff:g>?"</string>
<string name="never_ask_again" msgid="4295278542972859268">"No volver a preguntar"</string>
<string name="allow" msgid="7225948811296386551">"Permitir"</string>
@@ -121,7 +122,16 @@
</plurals>
<string name="delete_filename_confirmation_message" msgid="5312817725577537488">"¿Deseas borrar \"<xliff:g id="NAME">%1$s</xliff:g>\"?"</string>
<string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"¿Deseas borrar la carpeta \"<xliff:g id="NAME">%1$s</xliff:g>\" y su contenido?"</string>
- <!-- no translation found for delete_files_confirmation_message (8417505791395471802) -->
- <!-- no translation found for delete_folders_confirmation_message (9185648028213507769) -->
- <!-- no translation found for delete_items_confirmation_message (5376214433530243459) -->
+ <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+ <item quantity="other">¿Deseas borrar <xliff:g id="COUNT_1">%1$d</xliff:g> archivos?</item>
+ <item quantity="one">¿Deseas borrar <xliff:g id="COUNT_0">%1$d</xliff:g> archivo?</item>
+ </plurals>
+ <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+ <item quantity="other">¿Deseas borrar <xliff:g id="COUNT_1">%1$d</xliff:g> carpetas y su contenido?</item>
+ <item quantity="one">¿Deseas borrar <xliff:g id="COUNT_0">%1$d</xliff:g> carpeta y su contenido?</item>
+ </plurals>
+ <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+ <item quantity="other">¿Deseas borrar <xliff:g id="COUNT_1">%1$d</xliff:g> elementos?</item>
+ <item quantity="one">¿Deseas borrar <xliff:g id="COUNT_0">%1$d</xliff:g> elemento?</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-es/strings.xml b/packages/DocumentsUI/res/values-es/strings.xml
index a0da06c..9054561 100644
--- a/packages/DocumentsUI/res/values-es/strings.xml
+++ b/packages/DocumentsUI/res/values-es/strings.xml
@@ -111,7 +111,8 @@
<string name="rename_error" msgid="4203041674883412606">"Error al cambiar el nombre del documento"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Se han convertido algunos archivos"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"¿Permitir que <xliff:g id="APPNAME"><b>^1</b></xliff:g> acceda al directorio <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> (<xliff:g id="STORAGE"><i>^3</i></xliff:g>)?"</string>
- <string name="open_external_dialog_root_request" msgid="8899108702926347720">"¿Permitir que <xliff:g id="APPNAME"><b>^1</b></xliff:g> acceda a tus datos, incluidos los vídeos y las fotos de <xliff:g id="STORAGE"><i>^2</i></xliff:g>?"</string>
+ <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"¿Permitir que <xliff:g id="APPNAME"><b>^1</b></xliff:g> acceda al directorio <xliff:g id="DIRECTORY"><i>^2</i></xliff:g>?"</string>
+ <string name="open_external_dialog_root_request" msgid="8899108702926347720">"¿Permitir que <xliff:g id="APPNAME"><b>^1</b></xliff:g> acceda a tus datos, incluidos los vídeos y las fotos, de <xliff:g id="STORAGE"><i>^2</i></xliff:g>?"</string>
<string name="never_ask_again" msgid="4295278542972859268">"No volver a preguntar"</string>
<string name="allow" msgid="7225948811296386551">"Permitir"</string>
<string name="deny" msgid="2081879885755434506">"Denegar"</string>
@@ -121,7 +122,16 @@
</plurals>
<string name="delete_filename_confirmation_message" msgid="5312817725577537488">"¿Eliminar <xliff:g id="NAME">%1$s</xliff:g>?"</string>
<string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"¿Eliminar la carpeta <xliff:g id="NAME">%1$s</xliff:g> y su contenido?"</string>
- <!-- no translation found for delete_files_confirmation_message (8417505791395471802) -->
- <!-- no translation found for delete_folders_confirmation_message (9185648028213507769) -->
- <!-- no translation found for delete_items_confirmation_message (5376214433530243459) -->
+ <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+ <item quantity="other">¿Eliminar <xliff:g id="COUNT_1">%1$d</xliff:g> archivos?</item>
+ <item quantity="one">¿Eliminar <xliff:g id="COUNT_0">%1$d</xliff:g> archivo?</item>
+ </plurals>
+ <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+ <item quantity="other">¿Eliminar <xliff:g id="COUNT_1">%1$d</xliff:g> carpetas y su contenido?</item>
+ <item quantity="one">¿Eliminar <xliff:g id="COUNT_0">%1$d</xliff:g> carpeta y su contenido?</item>
+ </plurals>
+ <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+ <item quantity="other">¿Eliminar <xliff:g id="COUNT_1">%1$d</xliff:g> elementos?</item>
+ <item quantity="one">¿Eliminar <xliff:g id="COUNT_0">%1$d</xliff:g> elemento?</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-et-rEE/strings.xml b/packages/DocumentsUI/res/values-et-rEE/strings.xml
index d49b320..4bb2a9b 100644
--- a/packages/DocumentsUI/res/values-et-rEE/strings.xml
+++ b/packages/DocumentsUI/res/values-et-rEE/strings.xml
@@ -111,6 +111,7 @@
<string name="rename_error" msgid="4203041674883412606">"Dokumendi ümbernimetamine ebaõnnestus"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Mõned failid teisendati"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"Kas anda rakendusele <xliff:g id="APPNAME"><b>^1</b></xliff:g> juurdepääs kataloogile <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> salvestusruumis <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
+ <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Kas anda rakendusele <xliff:g id="APPNAME"><b>^1</b></xliff:g> juurdepääs kataloogile <xliff:g id="DIRECTORY"><i>^2</i></xliff:g>?"</string>
<string name="open_external_dialog_root_request" msgid="8899108702926347720">"Kas anda rakendusele <xliff:g id="APPNAME"><b>^1</b></xliff:g> juurdepääs teie andmetele (sh fotod ja videod) salvestusruumis <xliff:g id="STORAGE"><i>^2</i></xliff:g>?"</string>
<string name="never_ask_again" msgid="4295278542972859268">"Ära enam küsi"</string>
<string name="allow" msgid="7225948811296386551">"Luba"</string>
@@ -121,7 +122,16 @@
</plurals>
<string name="delete_filename_confirmation_message" msgid="5312817725577537488">"Kas kustutada fail „<xliff:g id="NAME">%1$s</xliff:g>”?"</string>
<string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"Kas kustutada kaust „<xliff:g id="NAME">%1$s</xliff:g>” ja selle sisu?"</string>
- <!-- no translation found for delete_files_confirmation_message (8417505791395471802) -->
- <!-- no translation found for delete_folders_confirmation_message (9185648028213507769) -->
- <!-- no translation found for delete_items_confirmation_message (5376214433530243459) -->
+ <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+ <item quantity="other">Kas kustutada <xliff:g id="COUNT_1">%1$d</xliff:g> faili?</item>
+ <item quantity="one">Kas kustutada <xliff:g id="COUNT_0">%1$d</xliff:g> fail?</item>
+ </plurals>
+ <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+ <item quantity="other">Kas kustutada <xliff:g id="COUNT_1">%1$d</xliff:g> kausta ja nende sisu?</item>
+ <item quantity="one">Kas kustutada <xliff:g id="COUNT_0">%1$d</xliff:g> kaust ja selle sisu?</item>
+ </plurals>
+ <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+ <item quantity="other">Kas kustutada <xliff:g id="COUNT_1">%1$d</xliff:g> üksust?</item>
+ <item quantity="one">Kas kustutada <xliff:g id="COUNT_0">%1$d</xliff:g> üksus?</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-eu-rES/strings.xml b/packages/DocumentsUI/res/values-eu-rES/strings.xml
index 085f148..d2bf89d 100644
--- a/packages/DocumentsUI/res/values-eu-rES/strings.xml
+++ b/packages/DocumentsUI/res/values-eu-rES/strings.xml
@@ -111,6 +111,7 @@
<string name="rename_error" msgid="4203041674883412606">"Ezin izan zaio aldatu izena dokumentuari"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Artxibo batzuk bihurtu dira"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> aplikazioari <xliff:g id="STORAGE"><i>^3</i></xliff:g> unitateko <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> direktorioa atzitzeko baimena eman nahi diozu?"</string>
+ <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> aplikazioari <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> direktoriorako sarbidea eman nahi diozu?"</string>
<string name="open_external_dialog_root_request" msgid="8899108702926347720">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> aplikazioari zure datuak atzitzea baimendu nahi diozu, besteak beste, <xliff:g id="STORAGE"><i>^2</i></xliff:g> biltegian dituzun argazkiak eta bideoak?"</string>
<string name="never_ask_again" msgid="4295278542972859268">"Ez galdetu berriro"</string>
<string name="allow" msgid="7225948811296386551">"Onartu"</string>
@@ -121,7 +122,16 @@
</plurals>
<string name="delete_filename_confirmation_message" msgid="5312817725577537488">"\"<xliff:g id="NAME">%1$s</xliff:g>\" ezabatu nahi duzu?"</string>
<string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"\"<xliff:g id="NAME">%1$s</xliff:g>\" karpeta eta bertako edukia ezabatu nahi duzu?"</string>
- <!-- no translation found for delete_files_confirmation_message (8417505791395471802) -->
- <!-- no translation found for delete_folders_confirmation_message (9185648028213507769) -->
- <!-- no translation found for delete_items_confirmation_message (5376214433530243459) -->
+ <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> fitxategi ezabatu nahi dituzu?</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> fitxategi ezabatu nahi duzu?</item>
+ </plurals>
+ <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> karpeta eta beren eduki guztia ezabatu nahi duzu?</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> karpeta eta bere eduki guztia ezabatu nahi duzu?</item>
+ </plurals>
+ <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> elementu ezabatu nahi dituzu?</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> elementu ezabatu nahi duzu?</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-fa/strings.xml b/packages/DocumentsUI/res/values-fa/strings.xml
index 114c7d0..1a4c035 100644
--- a/packages/DocumentsUI/res/values-fa/strings.xml
+++ b/packages/DocumentsUI/res/values-fa/strings.xml
@@ -111,6 +111,7 @@
<string name="rename_error" msgid="4203041674883412606">"نام سند تغییر نکرد"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"بعضی از فایلها تبدیل شدند"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"به <xliff:g id="APPNAME"><b>^1</b></xliff:g> اجازه داده شود به فهرست راهنمای <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> در <xliff:g id="STORAGE"><i>^3</i></xliff:g> دسترسی داشته باشد؟"</string>
+ <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"به <xliff:g id="APPNAME"><b>^1</b></xliff:g> اجازه دسترسی به دایرکتوری <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> داده شود؟"</string>
<string name="open_external_dialog_root_request" msgid="8899108702926347720">"به <xliff:g id="APPNAME"><b>^1</b></xliff:g> اجازه میدهید به دادههایتان دسترسی پیدا کند، از جمله عکسها و ویدیوهایتان در <xliff:g id="STORAGE"><i>^2</i></xliff:g>؟"</string>
<string name="never_ask_again" msgid="4295278542972859268">"دوباره سؤال نشود"</string>
<string name="allow" msgid="7225948811296386551">"ارزیابیشده"</string>
@@ -119,11 +120,18 @@
<item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> مورد انتخاب شد</item>
<item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> مورد انتخاب شد</item>
</plurals>
- <!-- no translation found for delete_filename_confirmation_message (5312817725577537488) -->
- <skip />
- <!-- no translation found for delete_foldername_confirmation_message (5885501832257285329) -->
- <skip />
- <!-- no translation found for delete_files_confirmation_message (8417505791395471802) -->
- <!-- no translation found for delete_folders_confirmation_message (9185648028213507769) -->
- <!-- no translation found for delete_items_confirmation_message (5376214433530243459) -->
+ <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"«<xliff:g id="NAME">%1$s</xliff:g>» حذف شود؟"</string>
+ <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"پوشه «<xliff:g id="NAME">%1$s</xliff:g>» و محتوای آن حذف شود؟"</string>
+ <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+ <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> فایل حذف شود؟</item>
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> فایل حذف شود؟</item>
+ </plurals>
+ <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+ <item quantity="one"> <xliff:g id="COUNT_1">%1$d</xliff:g> پوشه و محتوای آنها حذف شود؟</item>
+ <item quantity="other"> <xliff:g id="COUNT_1">%1$d</xliff:g> پوشه و محتوای آنها حذف شود؟</item>
+ </plurals>
+ <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+ <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> مورد حذف شود؟</item>
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> مورد حذف شود؟</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-fi/strings.xml b/packages/DocumentsUI/res/values-fi/strings.xml
index 46f863f..dfcfe89 100644
--- a/packages/DocumentsUI/res/values-fi/strings.xml
+++ b/packages/DocumentsUI/res/values-fi/strings.xml
@@ -111,6 +111,7 @@
<string name="rename_error" msgid="4203041674883412606">"Dokumentin nimen muuttaminen epäonnistui."</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Joitakin tiedostoja muunnettiin."</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"Myönnetäänkö sovellukselle <xliff:g id="APPNAME"><b>^1</b></xliff:g> sijainnissa <xliff:g id="STORAGE"><i>^3</i></xliff:g> olevan hakemiston <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> käyttöoikeus?"</string>
+ <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Saako <xliff:g id="APPNAME"><b>^1</b></xliff:g> käyttää hakemistoa <xliff:g id="DIRECTORY"><i>^2</i></xliff:g>?"</string>
<string name="open_external_dialog_root_request" msgid="8899108702926347720">"Myönnetäänkö sovellukselle <xliff:g id="APPNAME"><b>^1</b></xliff:g> sijainnissa <xliff:g id="STORAGE"><i>^2</i></xliff:g> olevien tietojesi, mukaan lukien valokuviesi ja videoidesi, käyttöoikeus?"</string>
<string name="never_ask_again" msgid="4295278542972859268">"Älä kysy uudestaan"</string>
<string name="allow" msgid="7225948811296386551">"Salli"</string>
@@ -121,7 +122,16 @@
</plurals>
<string name="delete_filename_confirmation_message" msgid="5312817725577537488">"Poistetaanko <xliff:g id="NAME">%1$s</xliff:g>?"</string>
<string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"Poistetaanko kansio <xliff:g id="NAME">%1$s</xliff:g> ja sen sisältö?"</string>
- <!-- no translation found for delete_files_confirmation_message (8417505791395471802) -->
- <!-- no translation found for delete_folders_confirmation_message (9185648028213507769) -->
- <!-- no translation found for delete_items_confirmation_message (5376214433530243459) -->
+ <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+ <item quantity="other">Poistetaanko <xliff:g id="COUNT_1">%1$d</xliff:g> tiedostoa?</item>
+ <item quantity="one">Poistetaanko <xliff:g id="COUNT_0">%1$d</xliff:g> tiedosto?</item>
+ </plurals>
+ <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+ <item quantity="other">Poistetaanko <xliff:g id="COUNT_1">%1$d</xliff:g> kansiota ja niiden sisältö?</item>
+ <item quantity="one">Poistetaanko <xliff:g id="COUNT_0">%1$d</xliff:g> kansio ja sen sisältö?</item>
+ </plurals>
+ <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+ <item quantity="other">Poistetaanko <xliff:g id="COUNT_1">%1$d</xliff:g> kohdetta?</item>
+ <item quantity="one">Poistetaanko <xliff:g id="COUNT_0">%1$d</xliff:g> kohde?</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-fr-rCA/strings.xml b/packages/DocumentsUI/res/values-fr-rCA/strings.xml
index b78b10e..543e226 100644
--- a/packages/DocumentsUI/res/values-fr-rCA/strings.xml
+++ b/packages/DocumentsUI/res/values-fr-rCA/strings.xml
@@ -111,6 +111,7 @@
<string name="rename_error" msgid="4203041674883412606">"Impossible de renommer le document"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Certains fichiers ont été convertis"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"Accorder à <xliff:g id="APPNAME"><b>^1</b></xliff:g> l\'accès au répertoire <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> sur <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
+ <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Accorder à <xliff:g id="APPNAME"><b>^1</b></xliff:g> l\'accès au répertoire <xliff:g id="DIRECTORY"><i>^2</i></xliff:g>?"</string>
<string name="open_external_dialog_root_request" msgid="8899108702926347720">"Voulez-vous accorder l\'accès à vos données à <xliff:g id="APPNAME"><b>^1</b></xliff:g>, y compris vos photos et vos vidéos, sur <xliff:g id="STORAGE"><i>^2</i></xliff:g>?"</string>
<string name="never_ask_again" msgid="4295278542972859268">"Ne plus me demander"</string>
<string name="allow" msgid="7225948811296386551">"Autoriser"</string>
@@ -121,7 +122,16 @@
</plurals>
<string name="delete_filename_confirmation_message" msgid="5312817725577537488">"Supprimer « <xliff:g id="NAME">%1$s</xliff:g> »?"</string>
<string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"Supprimer le dossier « <xliff:g id="NAME">%1$s</xliff:g> » et son contenu?"</string>
- <!-- no translation found for delete_files_confirmation_message (8417505791395471802) -->
- <!-- no translation found for delete_folders_confirmation_message (9185648028213507769) -->
- <!-- no translation found for delete_items_confirmation_message (5376214433530243459) -->
+ <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+ <item quantity="one">Supprimer <xliff:g id="COUNT_1">%1$d</xliff:g> fichier?</item>
+ <item quantity="other">Supprimer <xliff:g id="COUNT_1">%1$d</xliff:g> fichiers?</item>
+ </plurals>
+ <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+ <item quantity="one">Supprimer <xliff:g id="COUNT_1">%1$d</xliff:g> dossier et son contenu?</item>
+ <item quantity="other">Supprimer <xliff:g id="COUNT_1">%1$d</xliff:g> dossiers et leur contenu?</item>
+ </plurals>
+ <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+ <item quantity="one">Supprimer <xliff:g id="COUNT_1">%1$d</xliff:g> élément?</item>
+ <item quantity="other">Supprimer <xliff:g id="COUNT_1">%1$d</xliff:g> éléments?</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-fr/strings.xml b/packages/DocumentsUI/res/values-fr/strings.xml
index 63e28bf..05716d7 100644
--- a/packages/DocumentsUI/res/values-fr/strings.xml
+++ b/packages/DocumentsUI/res/values-fr/strings.xml
@@ -111,6 +111,7 @@
<string name="rename_error" msgid="4203041674883412606">"Échec du changement de nom du document."</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Certains fichiers ont été convertis"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"Autoriser <xliff:g id="APPNAME"><b>^1</b></xliff:g> à accéder à l\'annuaire \"<xliff:g id="DIRECTORY"><i>^2</i></xliff:g>\" sur <xliff:g id="STORAGE"><i>^3</i></xliff:g> ?"</string>
+ <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Autoriser <xliff:g id="APPNAME"><b>^1</b></xliff:g> à accéder à l\'annuaire \"<xliff:g id="DIRECTORY"><i>^2</i></xliff:g>\" ?"</string>
<string name="open_external_dialog_root_request" msgid="8899108702926347720">"Autoriser <xliff:g id="APPNAME"><b>^1</b></xliff:g> à accéder à vos données, y compris les photos et les vidéos, sur <xliff:g id="STORAGE"><i>^2</i></xliff:g> ?"</string>
<string name="never_ask_again" msgid="4295278542972859268">"Ne plus demander"</string>
<string name="allow" msgid="7225948811296386551">"Autoriser"</string>
@@ -121,7 +122,16 @@
</plurals>
<string name="delete_filename_confirmation_message" msgid="5312817725577537488">"Supprimer \"<xliff:g id="NAME">%1$s</xliff:g>\" ?"</string>
<string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"Supprimer le dossier \"<xliff:g id="NAME">%1$s</xliff:g>\" et son contenu ?"</string>
- <!-- no translation found for delete_files_confirmation_message (8417505791395471802) -->
- <!-- no translation found for delete_folders_confirmation_message (9185648028213507769) -->
- <!-- no translation found for delete_items_confirmation_message (5376214433530243459) -->
+ <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+ <item quantity="one">Supprimer <xliff:g id="COUNT_1">%1$d</xliff:g> fichier ?</item>
+ <item quantity="other">Supprimer <xliff:g id="COUNT_1">%1$d</xliff:g> fichiers ?</item>
+ </plurals>
+ <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+ <item quantity="one">Supprimer <xliff:g id="COUNT_1">%1$d</xliff:g> dossier et son contenu ?</item>
+ <item quantity="other">Supprimer <xliff:g id="COUNT_1">%1$d</xliff:g> dossiers et leur contenu ?</item>
+ </plurals>
+ <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+ <item quantity="one">Supprimer <xliff:g id="COUNT_1">%1$d</xliff:g> élément ?</item>
+ <item quantity="other">Supprimer <xliff:g id="COUNT_1">%1$d</xliff:g> éléments ?</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-gl-rES/strings.xml b/packages/DocumentsUI/res/values-gl-rES/strings.xml
index c4a77aa..5797a96 100644
--- a/packages/DocumentsUI/res/values-gl-rES/strings.xml
+++ b/packages/DocumentsUI/res/values-gl-rES/strings.xml
@@ -111,7 +111,8 @@
<string name="rename_error" msgid="4203041674883412606">"Non se puido cambiar o nome do documento"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Convertéronse algúns ficheiros"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"Queres outorgar acceso a <xliff:g id="APPNAME"><b>^1</b></xliff:g> ao directorio <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> no almacenamento de <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
- <string name="open_external_dialog_root_request" msgid="8899108702926347720">"Queres outorgar acceso a <xliff:g id="APPNAME"><b>^1</b></xliff:g> aos teus datos, incluídas as fotos e os vídeos da <xliff:g id="STORAGE"><i>^2</i></xliff:g>?"</string>
+ <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Queres darlle acceso a <xliff:g id="APPNAME"><b>^1</b></xliff:g> ao directorio <xliff:g id="DIRECTORY"><i>^2</i></xliff:g>?"</string>
+ <string name="open_external_dialog_root_request" msgid="8899108702926347720">"Queres darlle acceso a <xliff:g id="APPNAME"><b>^1</b></xliff:g> aos teus datos almacenados en <xliff:g id="STORAGE"><i>^2</i></xliff:g>, incluídos vídeos e fotos?"</string>
<string name="never_ask_again" msgid="4295278542972859268">"Non preguntar de novo"</string>
<string name="allow" msgid="7225948811296386551">"Permitir"</string>
<string name="deny" msgid="2081879885755434506">"Rexeitar"</string>
@@ -121,7 +122,16 @@
</plurals>
<string name="delete_filename_confirmation_message" msgid="5312817725577537488">"Queres eliminar \"<xliff:g id="NAME">%1$s</xliff:g>\"?"</string>
<string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"Queres eliminar o cartafol \"<xliff:g id="NAME">%1$s</xliff:g>\" e o seu contido?"</string>
- <!-- no translation found for delete_files_confirmation_message (8417505791395471802) -->
- <!-- no translation found for delete_folders_confirmation_message (9185648028213507769) -->
- <!-- no translation found for delete_items_confirmation_message (5376214433530243459) -->
+ <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+ <item quantity="other">Queres eliminar <xliff:g id="COUNT_1">%1$d</xliff:g> ficheiros?</item>
+ <item quantity="one">Queres eliminar <xliff:g id="COUNT_0">%1$d</xliff:g> ficheiro?</item>
+ </plurals>
+ <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+ <item quantity="other">Queres eliminar <xliff:g id="COUNT_1">%1$d</xliff:g> cartafoles e os seus contidos?</item>
+ <item quantity="one">Queres eliminar <xliff:g id="COUNT_0">%1$d</xliff:g> cartafol e os seus contidos?</item>
+ </plurals>
+ <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+ <item quantity="other">Queres eliminar <xliff:g id="COUNT_1">%1$d</xliff:g> elementos?</item>
+ <item quantity="one">Queres eliminar <xliff:g id="COUNT_0">%1$d</xliff:g> elemento?</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-gu-rIN/strings.xml b/packages/DocumentsUI/res/values-gu-rIN/strings.xml
index 6c2bb3e..48e43c4 100644
--- a/packages/DocumentsUI/res/values-gu-rIN/strings.xml
+++ b/packages/DocumentsUI/res/values-gu-rIN/strings.xml
@@ -111,6 +111,7 @@
<string name="rename_error" msgid="4203041674883412606">"દસ્તાવેજનું નામ બદલવામાં નિષ્ફળ થયાં"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"કેટલીક ફાઇલો રૂપાંતરિત કરી હતી"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> ને <xliff:g id="STORAGE"><i>^3</i></xliff:g> પર <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> નિર્દેશિકાની ઍક્સેસ આપીએ?"</string>
+ <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> ને <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> નિર્દેશિકાની ઍક્સેસ આપીએ?"</string>
<string name="open_external_dialog_root_request" msgid="8899108702926347720">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> ને <xliff:g id="STORAGE"><i>^2</i></xliff:g> પર ફોટા અને વિડિઓઝ સહિત તમારા ડેટાની અૅક્સેસ આપીએ?"</string>
<string name="never_ask_again" msgid="4295278542972859268">"ફરીથી પૂછશો નહીં"</string>
<string name="allow" msgid="7225948811296386551">"મંજૂરી આપો"</string>
@@ -121,7 +122,16 @@
</plurals>
<string name="delete_filename_confirmation_message" msgid="5312817725577537488">"\"<xliff:g id="NAME">%1$s</xliff:g>\" ને કાઢી નાખીએ?"</string>
<string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"\"<xliff:g id="NAME">%1$s</xliff:g>\" ફોલ્ડર અને તેની સામગ્રીઓને કાઢી નાખીએ?"</string>
- <!-- no translation found for delete_files_confirmation_message (8417505791395471802) -->
- <!-- no translation found for delete_folders_confirmation_message (9185648028213507769) -->
- <!-- no translation found for delete_items_confirmation_message (5376214433530243459) -->
+ <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+ <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> ફાઇલ કાઢી નાખીએ?</item>
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ફાઇલ કાઢી નાખીએ?</item>
+ </plurals>
+ <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+ <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> ફોલ્ડર અને તેમની સામગ્રીઓ કાઢી નાખીએ?</item>
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ફોલ્ડર અને તેમની સામગ્રીઓ કાઢી નાખીએ?</item>
+ </plurals>
+ <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+ <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> આઇટમ કાઢી નાખીએ?</item>
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> આઇટમ કાઢી નાખીએ?</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-hi/strings.xml b/packages/DocumentsUI/res/values-hi/strings.xml
index 9c27556..fa82ee8 100644
--- a/packages/DocumentsUI/res/values-hi/strings.xml
+++ b/packages/DocumentsUI/res/values-hi/strings.xml
@@ -111,6 +111,7 @@
<string name="rename_error" msgid="4203041674883412606">"दस्तावेज़ का नाम बदलना विफल रहा"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"कुछ फ़ाइलें रूपांतरित हो गई थीं"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> को <xliff:g id="STORAGE"><i>^3</i></xliff:g> पर <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> निर्देशिका का एक्सेस दें?"</string>
+ <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> को <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> निर्देशिका का एक्सेस प्रदान करें?"</string>
<string name="open_external_dialog_root_request" msgid="8899108702926347720">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> को <xliff:g id="STORAGE"><i>^2</i></xliff:g> पर मौजूद फ़ोटो और वीडियो सहित, अपने डेटा का एक्सेस प्रदान करें?"</string>
<string name="never_ask_again" msgid="4295278542972859268">"फिर से ना पूछें"</string>
<string name="allow" msgid="7225948811296386551">"अनुमति दें"</string>
@@ -121,7 +122,16 @@
</plurals>
<string name="delete_filename_confirmation_message" msgid="5312817725577537488">"\"<xliff:g id="NAME">%1$s</xliff:g>\" को हटाएं?"</string>
<string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"\"<xliff:g id="NAME">%1$s</xliff:g>\" फ़ोल्डर और उसकी सामग्रियां हटाएं?"</string>
- <!-- no translation found for delete_files_confirmation_message (8417505791395471802) -->
- <!-- no translation found for delete_folders_confirmation_message (9185648028213507769) -->
- <!-- no translation found for delete_items_confirmation_message (5376214433530243459) -->
+ <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+ <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> फ़ाइलें हटाएं?</item>
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> फ़ाइलें हटाएं?</item>
+ </plurals>
+ <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+ <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> फ़ोल्डर और उनकी सामग्री हटाएं?</item>
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> फ़ोल्डर और उनकी सामग्री हटाएं?</item>
+ </plurals>
+ <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+ <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> आइटम हटाएं?</item>
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> आइटम हटाएं?</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-hr/strings.xml b/packages/DocumentsUI/res/values-hr/strings.xml
index 58e709b..7988c71 100644
--- a/packages/DocumentsUI/res/values-hr/strings.xml
+++ b/packages/DocumentsUI/res/values-hr/strings.xml
@@ -118,6 +118,7 @@
<string name="rename_error" msgid="4203041674883412606">"Naziv dokumenta nije promijenjen"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Neke su datoteke konvertirane"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"Želite li aplikaciji <xliff:g id="APPNAME"><b>^1</b></xliff:g> odobriti pristup direktoriju <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> na pohrani <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
+ <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Želite li aplikaciji <xliff:g id="APPNAME"><b>^1</b></xliff:g> odobriti da pristupa direktoriju <xliff:g id="DIRECTORY"><i>^2</i></xliff:g>?"</string>
<string name="open_external_dialog_root_request" msgid="8899108702926347720">"Želite li aplikaciji <xliff:g id="APPNAME"><b>^1</b></xliff:g> dopustiti pristup podacima, uključujući fotografije i videozapise na vanjskoj pohrani (<xliff:g id="STORAGE"><i>^2</i></xliff:g>)?"</string>
<string name="never_ask_again" msgid="4295278542972859268">"Više me ne pitaj"</string>
<string name="allow" msgid="7225948811296386551">"Dopusti"</string>
@@ -129,7 +130,19 @@
</plurals>
<string name="delete_filename_confirmation_message" msgid="5312817725577537488">"Želite li izbrisati datoteku \"<xliff:g id="NAME">%1$s</xliff:g>\"?"</string>
<string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"Želite li izbrisati mapu \"<xliff:g id="NAME">%1$s</xliff:g>\" i njezin sadržaj?"</string>
- <!-- no translation found for delete_files_confirmation_message (8417505791395471802) -->
- <!-- no translation found for delete_folders_confirmation_message (9185648028213507769) -->
- <!-- no translation found for delete_items_confirmation_message (5376214433530243459) -->
+ <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+ <item quantity="one">Želite li izbrisati <xliff:g id="COUNT_1">%1$d</xliff:g> datoteku?</item>
+ <item quantity="few">Želite li izbrisati <xliff:g id="COUNT_1">%1$d</xliff:g> datoteke?</item>
+ <item quantity="other">Želite li izbrisati <xliff:g id="COUNT_1">%1$d</xliff:g> datoteka?</item>
+ </plurals>
+ <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+ <item quantity="one">Želite li izbrisati <xliff:g id="COUNT_1">%1$d</xliff:g> mapu i njihov sadržaj?</item>
+ <item quantity="few">Želite li izbrisati <xliff:g id="COUNT_1">%1$d</xliff:g> mape i njihov sadržaj?</item>
+ <item quantity="other">Želite li izbrisati <xliff:g id="COUNT_1">%1$d</xliff:g> mapa i njihov sadržaj?</item>
+ </plurals>
+ <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+ <item quantity="one">Želite li izbrisati <xliff:g id="COUNT_1">%1$d</xliff:g> stavku?</item>
+ <item quantity="few">Želite li izbrisati <xliff:g id="COUNT_1">%1$d</xliff:g> stavke?</item>
+ <item quantity="other">Želite li izbrisati <xliff:g id="COUNT_1">%1$d</xliff:g> stavki?</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-hu/strings.xml b/packages/DocumentsUI/res/values-hu/strings.xml
index 1936214..fb666b5 100644
--- a/packages/DocumentsUI/res/values-hu/strings.xml
+++ b/packages/DocumentsUI/res/values-hu/strings.xml
@@ -111,6 +111,7 @@
<string name="rename_error" msgid="4203041674883412606">"Nem sikerült átnevezni a dokumentumot"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Egyes fájlokat konvertált a rendszer"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"Hozzáférést biztosít a(z) <xliff:g id="APPNAME"><b>^1</b></xliff:g> számára a(z) <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> könyvtárhoz itt: <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
+ <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Hozzáférést biztosít a(z) <xliff:g id="APPNAME"><b>^1</b></xliff:g> alkalmazásnak a(z) <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> könyvtárhoz?"</string>
<string name="open_external_dialog_root_request" msgid="8899108702926347720">"Hozzáférést biztosít a(z) <xliff:g id="APPNAME"><b>^1</b></xliff:g> számára az Ön adataihoz, beleértve a következő tárhelyen található képekhez és videókhoz: <xliff:g id="STORAGE"><i>^2</i></xliff:g>?"</string>
<string name="never_ask_again" msgid="4295278542972859268">"Ne jelenjen meg többé"</string>
<string name="allow" msgid="7225948811296386551">"Engedélyezés"</string>
@@ -121,7 +122,16 @@
</plurals>
<string name="delete_filename_confirmation_message" msgid="5312817725577537488">"Törli a következőt: „<xliff:g id="NAME">%1$s</xliff:g>”?"</string>
<string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"Törli „<xliff:g id="NAME">%1$s</xliff:g>” mappát a tartalmával együtt?"</string>
- <!-- no translation found for delete_files_confirmation_message (8417505791395471802) -->
- <!-- no translation found for delete_folders_confirmation_message (9185648028213507769) -->
- <!-- no translation found for delete_items_confirmation_message (5376214433530243459) -->
+ <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+ <item quantity="other">Töröl <xliff:g id="COUNT_1">%1$d</xliff:g> fájlt?</item>
+ <item quantity="one">Töröl <xliff:g id="COUNT_0">%1$d</xliff:g> fájlt?</item>
+ </plurals>
+ <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+ <item quantity="other">Töröl <xliff:g id="COUNT_1">%1$d</xliff:g> mappát a tartalmukkal együtt?</item>
+ <item quantity="one">Töröl <xliff:g id="COUNT_0">%1$d</xliff:g> mappát a tartalmával együtt?</item>
+ </plurals>
+ <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+ <item quantity="other">Töröl <xliff:g id="COUNT_1">%1$d</xliff:g> elemet?</item>
+ <item quantity="one">Töröl <xliff:g id="COUNT_0">%1$d</xliff:g> elemet?</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-hy-rAM/strings.xml b/packages/DocumentsUI/res/values-hy-rAM/strings.xml
index 57af718..f6c3ad5 100644
--- a/packages/DocumentsUI/res/values-hy-rAM/strings.xml
+++ b/packages/DocumentsUI/res/values-hy-rAM/strings.xml
@@ -111,6 +111,7 @@
<string name="rename_error" msgid="4203041674883412606">"Չհաջողվեց վերանվանել փաստաթուղթը"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Որոշ ֆայլեր փոխարկվել են"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> հավելվածին տրամադրե՞լ <xliff:g id="STORAGE"><i>^3</i></xliff:g>-ի <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> գրացուցակն օգտագործելու թույլտվություն:"</string>
+ <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> հավելվածին տրամադրե՞լ <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> գրացուցակն օգտագործելու թույլտվություն:"</string>
<string name="open_external_dialog_root_request" msgid="8899108702926347720">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> հավելվածին տրամադրե՞լ <xliff:g id="STORAGE"><i>^2</i></xliff:g>-ում պահվող ձեր տվյալները, այդ թվում նաև լուսանկարները և տեսանյութերը, օգտագործելու թույլտվություն:"</string>
<string name="never_ask_again" msgid="4295278542972859268">"Այլևս չհարցնել"</string>
<string name="allow" msgid="7225948811296386551">"Թույլատրել"</string>
@@ -119,11 +120,18 @@
<item quantity="one">Ընտրված է՝ <xliff:g id="COUNT_1">%1$d</xliff:g></item>
<item quantity="other">Ընտրված է՝ <xliff:g id="COUNT_1">%1$d</xliff:g></item>
</plurals>
- <!-- no translation found for delete_filename_confirmation_message (5312817725577537488) -->
- <skip />
- <!-- no translation found for delete_foldername_confirmation_message (5885501832257285329) -->
- <skip />
- <!-- no translation found for delete_files_confirmation_message (8417505791395471802) -->
- <!-- no translation found for delete_folders_confirmation_message (9185648028213507769) -->
- <!-- no translation found for delete_items_confirmation_message (5376214433530243459) -->
+ <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"Ջնջե՞լ «<xliff:g id="NAME">%1$s</xliff:g>» ֆայլը:"</string>
+ <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"Ջնջե՞լ «<xliff:g id="NAME">%1$s</xliff:g>» պանակը՝ բովանդակության հետ մեկտեղ:"</string>
+ <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+ <item quantity="one">Ջնջե՞լ <xliff:g id="COUNT_1">%1$d</xliff:g> ֆայլ:</item>
+ <item quantity="other">Ջնջե՞լ <xliff:g id="COUNT_1">%1$d</xliff:g> ֆայլ:</item>
+ </plurals>
+ <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+ <item quantity="one">Ջնջե՞լ <xliff:g id="COUNT_1">%1$d</xliff:g> պանակ՝ բովանդակության հետ մեկտեղ:</item>
+ <item quantity="other">Ջնջե՞լ <xliff:g id="COUNT_1">%1$d</xliff:g> պանակ՝ բովանդակության հետ մեկտեղ:</item>
+ </plurals>
+ <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+ <item quantity="one">Ջնջե՞լ <xliff:g id="COUNT_1">%1$d</xliff:g> տարր:</item>
+ <item quantity="other">Ջնջե՞լ <xliff:g id="COUNT_1">%1$d</xliff:g> տարր:</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-in/strings.xml b/packages/DocumentsUI/res/values-in/strings.xml
index 6621c9171..a8aee52 100644
--- a/packages/DocumentsUI/res/values-in/strings.xml
+++ b/packages/DocumentsUI/res/values-in/strings.xml
@@ -111,6 +111,7 @@
<string name="rename_error" msgid="4203041674883412606">"Gagal mengganti nama dokumen"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Beberapa file dikonversi"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"Beri <xliff:g id="APPNAME"><b>^1</b></xliff:g> akses ke direktori <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> di <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
+ <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Beri <xliff:g id="APPNAME"><b>^1</b></xliff:g> akses ke direktori <xliff:g id="DIRECTORY"><i>^2</i></xliff:g>?"</string>
<string name="open_external_dialog_root_request" msgid="8899108702926347720">"Beri <xliff:g id="APPNAME"><b>^1</b></xliff:g> akses ke data Anda, termasuk foto dan video, di <xliff:g id="STORAGE"><i>^2</i></xliff:g>?"</string>
<string name="never_ask_again" msgid="4295278542972859268">"Jangan tanya lagi"</string>
<string name="allow" msgid="7225948811296386551">"Izinkan"</string>
@@ -121,7 +122,16 @@
</plurals>
<string name="delete_filename_confirmation_message" msgid="5312817725577537488">"Hapus \"<xliff:g id="NAME">%1$s</xliff:g>\"?"</string>
<string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"Hapus folder \"<xliff:g id="NAME">%1$s</xliff:g>\" dan kontennya?"</string>
- <!-- no translation found for delete_files_confirmation_message (8417505791395471802) -->
- <!-- no translation found for delete_folders_confirmation_message (9185648028213507769) -->
- <!-- no translation found for delete_items_confirmation_message (5376214433530243459) -->
+ <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+ <item quantity="other">Hapus <xliff:g id="COUNT_1">%1$d</xliff:g> file?</item>
+ <item quantity="one">Hapus <xliff:g id="COUNT_0">%1$d</xliff:g> file?</item>
+ </plurals>
+ <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+ <item quantity="other">Hapus <xliff:g id="COUNT_1">%1$d</xliff:g> folder dan kontennya?</item>
+ <item quantity="one">Hapus <xliff:g id="COUNT_0">%1$d</xliff:g> folder dan kontennya?</item>
+ </plurals>
+ <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+ <item quantity="other">Hapus <xliff:g id="COUNT_1">%1$d</xliff:g> item?</item>
+ <item quantity="one">Hapus <xliff:g id="COUNT_0">%1$d</xliff:g> item?</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-is-rIS/strings.xml b/packages/DocumentsUI/res/values-is-rIS/strings.xml
index 4265606..88aaced 100644
--- a/packages/DocumentsUI/res/values-is-rIS/strings.xml
+++ b/packages/DocumentsUI/res/values-is-rIS/strings.xml
@@ -111,6 +111,7 @@
<string name="rename_error" msgid="4203041674883412606">"Ekki tókst að endurnefna skjalið"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Sumum skrám var umbreytt"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"Veita <xliff:g id="APPNAME"><b>^1</b></xliff:g> aðgang að skráasafninu <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> á <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
+ <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Viltu veita <xliff:g id="APPNAME"><b>^1</b></xliff:g> aðgang að skráasafninu <xliff:g id="DIRECTORY"><i>^2</i></xliff:g>?"</string>
<string name="open_external_dialog_root_request" msgid="8899108702926347720">"Veita <xliff:g id="APPNAME"><b>^1</b></xliff:g> aðgang að gögnunum þínum, þar á meðal myndum og myndskeiðum, á <xliff:g id="STORAGE"><i>^2</i></xliff:g>?"</string>
<string name="never_ask_again" msgid="4295278542972859268">"Ekki spyrja aftur"</string>
<string name="allow" msgid="7225948811296386551">"Leyfa"</string>
@@ -121,7 +122,16 @@
</plurals>
<string name="delete_filename_confirmation_message" msgid="5312817725577537488">"Eyða „<xliff:g id="NAME">%1$s</xliff:g>“?"</string>
<string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"Eyða möppunni „<xliff:g id="NAME">%1$s</xliff:g>“ og öllu innihaldi hennar?"</string>
- <!-- no translation found for delete_files_confirmation_message (8417505791395471802) -->
- <!-- no translation found for delete_folders_confirmation_message (9185648028213507769) -->
- <!-- no translation found for delete_items_confirmation_message (5376214433530243459) -->
+ <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+ <item quantity="one">Eyða <xliff:g id="COUNT_1">%1$d</xliff:g> skrá?</item>
+ <item quantity="other">Eyða <xliff:g id="COUNT_1">%1$d</xliff:g> skrám?</item>
+ </plurals>
+ <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+ <item quantity="one">Eyða <xliff:g id="COUNT_1">%1$d</xliff:g> möppu og innihaldi þeirra?</item>
+ <item quantity="other">Eyða <xliff:g id="COUNT_1">%1$d</xliff:g> möppum og innihaldi þeirra?</item>
+ </plurals>
+ <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+ <item quantity="one">Eyða <xliff:g id="COUNT_1">%1$d</xliff:g> atriði?</item>
+ <item quantity="other">Eyða <xliff:g id="COUNT_1">%1$d</xliff:g> atriðum?</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-it/strings.xml b/packages/DocumentsUI/res/values-it/strings.xml
index 7599180..b7497db 100644
--- a/packages/DocumentsUI/res/values-it/strings.xml
+++ b/packages/DocumentsUI/res/values-it/strings.xml
@@ -111,6 +111,7 @@
<string name="rename_error" msgid="4203041674883412606">"Ridenominazione documento non riuscita"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Alcuni file sono stati convertiti"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"Concedere all\'app <xliff:g id="APPNAME"><b>^1</b></xliff:g> l\'accesso alla directory <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> su <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
+ <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Concedere all\'app <xliff:g id="APPNAME"><b>^1</b></xliff:g> l\'accesso alla directory <xliff:g id="DIRECTORY"><i>^2</i></xliff:g>?"</string>
<string name="open_external_dialog_root_request" msgid="8899108702926347720">"Concedere all\'app <xliff:g id="APPNAME"><b>^1</b></xliff:g> l\'accesso ai tuoi dati, inclusi video e foto, sull\'unità <xliff:g id="STORAGE"><i>^2</i></xliff:g>?"</string>
<string name="never_ask_again" msgid="4295278542972859268">"Non chiedermelo più"</string>
<string name="allow" msgid="7225948811296386551">"Consenti"</string>
@@ -121,7 +122,16 @@
</plurals>
<string name="delete_filename_confirmation_message" msgid="5312817725577537488">"Eliminare \"<xliff:g id="NAME">%1$s</xliff:g>\"?"</string>
<string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"Eliminare la cartella \"<xliff:g id="NAME">%1$s</xliff:g>\" e i relativi contenuti?"</string>
- <!-- no translation found for delete_files_confirmation_message (8417505791395471802) -->
- <!-- no translation found for delete_folders_confirmation_message (9185648028213507769) -->
- <!-- no translation found for delete_items_confirmation_message (5376214433530243459) -->
+ <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+ <item quantity="other">Eliminare <xliff:g id="COUNT_1">%1$d</xliff:g> file?</item>
+ <item quantity="one">Eliminare <xliff:g id="COUNT_0">%1$d</xliff:g> file?</item>
+ </plurals>
+ <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+ <item quantity="other">Eliminare <xliff:g id="COUNT_1">%1$d</xliff:g> cartelle e i relativi contenuti?</item>
+ <item quantity="one">Eliminare <xliff:g id="COUNT_0">%1$d</xliff:g> cartella e i relativi contenuti?</item>
+ </plurals>
+ <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+ <item quantity="other">Eliminare <xliff:g id="COUNT_1">%1$d</xliff:g> elementi?</item>
+ <item quantity="one">Eliminare <xliff:g id="COUNT_0">%1$d</xliff:g> elemento?</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-iw/strings.xml b/packages/DocumentsUI/res/values-iw/strings.xml
index 2e2020c..4498f8c 100644
--- a/packages/DocumentsUI/res/values-iw/strings.xml
+++ b/packages/DocumentsUI/res/values-iw/strings.xml
@@ -125,6 +125,7 @@
<string name="rename_error" msgid="4203041674883412606">"ניסיון שינוי שם המסמך נכשל"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"קבצים מסוימים הומרו"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"האם להעניק לאפליקציה <xliff:g id="APPNAME"><b>^1</b></xliff:g> גישה לספריה <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> באחסון <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
+ <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"האם להעניק לאפליקציה <xliff:g id="APPNAME"><b>^1</b></xliff:g> גישה אל ספריית <xliff:g id="DIRECTORY"><i>^2</i></xliff:g>?"</string>
<string name="open_external_dialog_root_request" msgid="8899108702926347720">"האם להעניק לאפליקציה <xliff:g id="APPNAME"><b>^1</b></xliff:g> גישה לנתונים שלך, כולל תמונות וסרטונים, השמורים ב<xliff:g id="STORAGE"><i>^2</i></xliff:g>?"</string>
<string name="never_ask_again" msgid="4295278542972859268">"אל תשאל שוב"</string>
<string name="allow" msgid="7225948811296386551">"אפשר"</string>
@@ -135,11 +136,24 @@
<item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> נבחרו</item>
<item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> נבחר</item>
</plurals>
- <!-- no translation found for delete_filename_confirmation_message (5312817725577537488) -->
- <skip />
- <!-- no translation found for delete_foldername_confirmation_message (5885501832257285329) -->
- <skip />
- <!-- no translation found for delete_files_confirmation_message (8417505791395471802) -->
- <!-- no translation found for delete_folders_confirmation_message (9185648028213507769) -->
- <!-- no translation found for delete_items_confirmation_message (5376214433530243459) -->
+ <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"האם למחוק את \"<xliff:g id="NAME">%1$s</xliff:g>\"?"</string>
+ <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"האם למחוק את התיקייה \"<xliff:g id="NAME">%1$s</xliff:g>\" ואת התוכן שלה?"</string>
+ <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+ <item quantity="two">האם למחוק <xliff:g id="COUNT_1">%1$d</xliff:g> קבצים?</item>
+ <item quantity="many">האם למחוק <xliff:g id="COUNT_1">%1$d</xliff:g> קבצים?</item>
+ <item quantity="other">האם למחוק <xliff:g id="COUNT_1">%1$d</xliff:g> קבצים?</item>
+ <item quantity="one">האם למחוק <xliff:g id="COUNT_0">%1$d</xliff:g> קובץ?</item>
+ </plurals>
+ <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+ <item quantity="two">האם למחוק <xliff:g id="COUNT_1">%1$d</xliff:g> תיקיות ואת התוכן שלהן?</item>
+ <item quantity="many">האם למחוק <xliff:g id="COUNT_1">%1$d</xliff:g> תיקיות ואת התוכן שלהן?</item>
+ <item quantity="other">האם למחוק <xliff:g id="COUNT_1">%1$d</xliff:g> תיקיות ואת התוכן שלהן?</item>
+ <item quantity="one">האם למחוק <xliff:g id="COUNT_0">%1$d</xliff:g> תיקייה ואת התוכן שלה?</item>
+ </plurals>
+ <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+ <item quantity="two">האם למחוק <xliff:g id="COUNT_1">%1$d</xliff:g> פריטים?</item>
+ <item quantity="many">האם למחוק <xliff:g id="COUNT_1">%1$d</xliff:g> פריטים?</item>
+ <item quantity="other">האם למחוק <xliff:g id="COUNT_1">%1$d</xliff:g> פריטים?</item>
+ <item quantity="one">האם למחוק <xliff:g id="COUNT_0">%1$d</xliff:g> פריט?</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-ja/strings.xml b/packages/DocumentsUI/res/values-ja/strings.xml
index 1ba405f..bfb1c3a 100644
--- a/packages/DocumentsUI/res/values-ja/strings.xml
+++ b/packages/DocumentsUI/res/values-ja/strings.xml
@@ -111,6 +111,7 @@
<string name="rename_error" msgid="4203041674883412606">"ドキュメントの名前を変更できませんでした"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"一部のファイルが変換されました"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"「<xliff:g id="STORAGE"><i>^3</i></xliff:g>」の「<xliff:g id="DIRECTORY"><i>^2</i></xliff:g>」ディレクトリに「<xliff:g id="APPNAME"><b>^1</b></xliff:g>」へのアクセスを許可しますか?"</string>
+ <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"「<xliff:g id="APPNAME"><b>^1</b></xliff:g>」アプリに「<xliff:g id="DIRECTORY"><i>^2</i></xliff:g>」ディレクトリへのアクセスを許可しますか?"</string>
<string name="open_external_dialog_root_request" msgid="8899108702926347720">"<xliff:g id="STORAGE"><i>^2</i></xliff:g>の写真や動画などのデータへのアクセスを「<xliff:g id="APPNAME"><b>^1</b></xliff:g>」に許可しますか?"</string>
<string name="never_ask_again" msgid="4295278542972859268">"今後表示しない"</string>
<string name="allow" msgid="7225948811296386551">"許可"</string>
@@ -121,7 +122,16 @@
</plurals>
<string name="delete_filename_confirmation_message" msgid="5312817725577537488">"「<xliff:g id="NAME">%1$s</xliff:g>」を削除しますか?"</string>
<string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"フォルダ「<xliff:g id="NAME">%1$s</xliff:g>」とそのコンテンツを削除しますか?"</string>
- <!-- no translation found for delete_files_confirmation_message (8417505791395471802) -->
- <!-- no translation found for delete_folders_confirmation_message (9185648028213507769) -->
- <!-- no translation found for delete_items_confirmation_message (5376214433530243459) -->
+ <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> 個のファイルを削除しますか?</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> 個のファイルを削除しますか?</item>
+ </plurals>
+ <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> 個のフォルダとそのコンテンツを削除しますか?</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> 個のフォルダとそのコンテンツを削除しますか?</item>
+ </plurals>
+ <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> 個の項目を削除しますか?</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> 個の項目を削除しますか?</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-ka-rGE/strings.xml b/packages/DocumentsUI/res/values-ka-rGE/strings.xml
index c1624e3..f0e9e86 100644
--- a/packages/DocumentsUI/res/values-ka-rGE/strings.xml
+++ b/packages/DocumentsUI/res/values-ka-rGE/strings.xml
@@ -111,6 +111,7 @@
<string name="rename_error" msgid="4203041674883412606">"დოკუმენტის გადარქმევა ვერ მოხერხდა"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"ზოგიერთი ფაილი გარდაქმნილია"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"გსურთ, <xliff:g id="APPNAME"><b>^1</b></xliff:g> სარგებლობდეს <xliff:g id="STORAGE"><i>^3</i></xliff:g>-ის დირექტორიაზე „<xliff:g id="DIRECTORY"><i>^2</i></xliff:g>“ წვდომის უფლებით?"</string>
+ <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"გსურთ, <xliff:g id="APPNAME"><b>^1</b></xliff:g> სარგებლობდეს დირექტორიაზე „<xliff:g id="DIRECTORY"><i>^2</i></xliff:g>“ წვდომის უფლებით?"</string>
<string name="open_external_dialog_root_request" msgid="8899108702926347720">"გსურთ, <xliff:g id="APPNAME"><b>^1</b></xliff:g> სარგებლობდეს <xliff:g id="STORAGE"><i>^2</i></xliff:g>-ზე არსებულ მონაცემებზე, მათ შორის, ფოტოებსა და ვიდეოებზე, წვდომის უფლებით?"</string>
<string name="never_ask_again" msgid="4295278542972859268">"აღარ მკითხოთ"</string>
<string name="allow" msgid="7225948811296386551">"უფლების მიცემა"</string>
@@ -119,11 +120,18 @@
<item quantity="other">არჩეულია <xliff:g id="COUNT_1">%1$d</xliff:g></item>
<item quantity="one">არჩეულია <xliff:g id="COUNT_0">%1$d</xliff:g></item>
</plurals>
- <!-- no translation found for delete_filename_confirmation_message (5312817725577537488) -->
- <skip />
- <!-- no translation found for delete_foldername_confirmation_message (5885501832257285329) -->
- <skip />
- <!-- no translation found for delete_files_confirmation_message (8417505791395471802) -->
- <!-- no translation found for delete_folders_confirmation_message (9185648028213507769) -->
- <!-- no translation found for delete_items_confirmation_message (5376214433530243459) -->
+ <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"გსურთ, წაშალოთ „<xliff:g id="NAME">%1$s</xliff:g>“?"</string>
+ <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"გსურთ, წაშალოთ საქაღალდე „<xliff:g id="NAME">%1$s</xliff:g>“ და მისი შიგთავსი?"</string>
+ <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+ <item quantity="other">გსურთ <xliff:g id="COUNT_1">%1$d</xliff:g> ფაილის წაშლა?</item>
+ <item quantity="one">გსურთ <xliff:g id="COUNT_0">%1$d</xliff:g> ფაილის წაშლა?</item>
+ </plurals>
+ <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+ <item quantity="other">გსურთ <xliff:g id="COUNT_1">%1$d</xliff:g> საქაღალდისა და მათი შიგთავსის წაშლა?</item>
+ <item quantity="one">გსურთ <xliff:g id="COUNT_0">%1$d</xliff:g> საქაღალდისა და მისი შიგთავსის წაშლა?</item>
+ </plurals>
+ <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+ <item quantity="other">გსურთ <xliff:g id="COUNT_1">%1$d</xliff:g> ერთეულის წაშლა?</item>
+ <item quantity="one">გსურთ <xliff:g id="COUNT_0">%1$d</xliff:g> ერთეულის წაშლა?</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-kk-rKZ/strings.xml b/packages/DocumentsUI/res/values-kk-rKZ/strings.xml
index 904ca5d..2687900 100644
--- a/packages/DocumentsUI/res/values-kk-rKZ/strings.xml
+++ b/packages/DocumentsUI/res/values-kk-rKZ/strings.xml
@@ -111,7 +111,8 @@
<string name="rename_error" msgid="4203041674883412606">"Құжат қайта аталмады"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Кейбір файлдар түрлендірілді"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> қолданбасына <xliff:g id="STORAGE"><i>^3</i></xliff:g> қоймасындағы <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> каталогына өтуге рұқсат беру керек пе?"</string>
- <string name="open_external_dialog_root_request" msgid="8899108702926347720">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> <xliff:g id="STORAGE"><i>^2</i></xliff:g> қоймасындағы деректерге, соның ішінде, фотосуреттерге және бейнелерге қатынас беру керек пе?"</string>
+ <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> қолданбасына <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> каталогына қатынас беру керек пе?"</string>
+ <string name="open_external_dialog_root_request" msgid="8899108702926347720">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> <xliff:g id="STORAGE"><i>^2</i></xliff:g> қоймасындағы деректерге, соның ішінде фотосуреттерге және бейнелерге кіру мүмкіндігін беру керек пе?"</string>
<string name="never_ask_again" msgid="4295278542972859268">"Қайта сұралмасын"</string>
<string name="allow" msgid="7225948811296386551">"Рұқсат беру"</string>
<string name="deny" msgid="2081879885755434506">"Бас тарту"</string>
@@ -121,7 +122,16 @@
</plurals>
<string name="delete_filename_confirmation_message" msgid="5312817725577537488">"\"<xliff:g id="NAME">%1$s</xliff:g>\" жою керек пе?"</string>
<string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"\"<xliff:g id="NAME">%1$s</xliff:g>\" қалтасын және оның мазмұнын жою керек пе?"</string>
- <!-- no translation found for delete_files_confirmation_message (8417505791395471802) -->
- <!-- no translation found for delete_folders_confirmation_message (9185648028213507769) -->
- <!-- no translation found for delete_items_confirmation_message (5376214433530243459) -->
+ <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> файлды жою керек пе?</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> файлды жою керек пе?</item>
+ </plurals>
+ <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> қалтаны ішіндегісімен бірге жою керек пе?</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> қалтаны ішіндегісімен бірге жою керек пе?</item>
+ </plurals>
+ <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> элементті жою керек пе?</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> элементті жою керек пе?</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-km-rKH/strings.xml b/packages/DocumentsUI/res/values-km-rKH/strings.xml
index ca0fa4c..ea24043 100644
--- a/packages/DocumentsUI/res/values-km-rKH/strings.xml
+++ b/packages/DocumentsUI/res/values-km-rKH/strings.xml
@@ -111,6 +111,7 @@
<string name="rename_error" msgid="4203041674883412606">"បានបរាជ័យក្នុងការប្តូរឈ្មោះឯកសារ"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"ឯកសារមួយចំនួនត្រូវបានបម្លែង"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"ផ្តល់សិទ្ធិឲ្យ <xliff:g id="APPNAME"><b>^1</b></xliff:g> ចូលដំណើរការថត <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> នៅលើ <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
+ <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"ផ្តល់សិទ្ធិឲ្យ <xliff:g id="APPNAME"><b>^1</b></xliff:g> ចូលដំណើរការថត <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> ឬ?"</string>
<string name="open_external_dialog_root_request" msgid="8899108702926347720">"ផ្តល់សិទ្ធិអនុញ្ញាតដល់ <xliff:g id="APPNAME"><b>^1</b></xliff:g> ដើម្បីចូលដំណើរការទិន្នន័យរបស់អ្នក រាប់បញ្ចូលទាំងរូបថត និងវីដេអូ នៅលើ <xliff:g id="STORAGE"><i>^2</i></xliff:g> ឬទេ?"</string>
<string name="never_ask_again" msgid="4295278542972859268">"កុំសួរទៀត"</string>
<string name="allow" msgid="7225948811296386551">"អនុញ្ញាត"</string>
@@ -121,7 +122,16 @@
</plurals>
<string name="delete_filename_confirmation_message" msgid="5312817725577537488">"លុប \"<xliff:g id="NAME">%1$s</xliff:g>\" ឬ?"</string>
<string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"លុបថតឯកសារ \"<xliff:g id="NAME">%1$s</xliff:g>\" និងមាតិការបស់វាឬ?"</string>
- <!-- no translation found for delete_files_confirmation_message (8417505791395471802) -->
- <!-- no translation found for delete_folders_confirmation_message (9185648028213507769) -->
- <!-- no translation found for delete_items_confirmation_message (5376214433530243459) -->
+ <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+ <item quantity="other">លុបឯកសារ <xliff:g id="COUNT_1">%1$d</xliff:g> ច្បាប់ឬ?</item>
+ <item quantity="one">លុបឯកសារ <xliff:g id="COUNT_0">%1$d</xliff:g> ច្បាប់ឬ?</item>
+ </plurals>
+ <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+ <item quantity="other">លុបថតឯកសារ <xliff:g id="COUNT_1">%1$d</xliff:g> និងមាតិការបស់វាឬ?</item>
+ <item quantity="one">លុបថតឯកសារ <xliff:g id="COUNT_0">%1$d</xliff:g> និងមាតិការបស់វាឬ?</item>
+ </plurals>
+ <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+ <item quantity="other">លុបធាតុ <xliff:g id="COUNT_1">%1$d</xliff:g> ឬ?</item>
+ <item quantity="one">លុបធាតុ <xliff:g id="COUNT_0">%1$d</xliff:g> ឬ?</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-kn-rIN/strings.xml b/packages/DocumentsUI/res/values-kn-rIN/strings.xml
index 6287274..c756009 100644
--- a/packages/DocumentsUI/res/values-kn-rIN/strings.xml
+++ b/packages/DocumentsUI/res/values-kn-rIN/strings.xml
@@ -111,6 +111,7 @@
<string name="rename_error" msgid="4203041674883412606">"ಡಾಕ್ಯುಮೆಂಟ್ ಮರುಹೆಸರಿಸಲು ವಿಫಲವಾಗಿದೆ"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"ಕೆಲವು ಫೈಲ್ಗಳನ್ನು ಪರಿವರ್ತಿಸಲಾಗಿದೆ"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"<xliff:g id="STORAGE"><i>^3</i></xliff:g> ರಲ್ಲಿ <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> ಡೈರೆಕ್ಟರಿಗೆ <xliff:g id="APPNAME"><b>^1</b></xliff:g> ಪ್ರವೇಶ ನೀಡುವುದೇ?"</string>
+ <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"<xliff:g id="APPNAME"><b>^1</b></xliff:g><xliff:g id="DIRECTORY"><i>^2</i></xliff:g> ಡೈರೆಕ್ಟರಿ ಪ್ರವೇಶಿಸಲು ಅನುಮತಿಸುವುದೇ?"</string>
<string name="open_external_dialog_root_request" msgid="8899108702926347720">"<xliff:g id="STORAGE"><i>^2</i></xliff:g> ಸಂಗ್ರಹಣೆಯಲ್ಲಿನ ಪೋಟೋಗಳು ಮತ್ತು ವೀಡಿಯೊಗಳು ಸೇರಿದಂತೆ ನಿಮ್ಮ ಡೇಟಾವನ್ನು ಪ್ರವೇಶಿಸಲು <xliff:g id="APPNAME"><b>^1</b></xliff:g> ಅಪ್ಲಿಕೇಶನ್ಗೆ ಅನುಮತಿಸುವುದೇ?"</string>
<string name="never_ask_again" msgid="4295278542972859268">"ಮತ್ತೆ ಕೇಳಬೇಡಿ"</string>
<string name="allow" msgid="7225948811296386551">"ಅನುಮತಿಸು"</string>
@@ -119,11 +120,18 @@
<item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> ಆಯ್ಕೆಮಾಡಲಾಗಿದೆ</item>
<item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ಆಯ್ಕೆಮಾಡಲಾಗಿದೆ</item>
</plurals>
- <!-- no translation found for delete_filename_confirmation_message (5312817725577537488) -->
- <skip />
- <!-- no translation found for delete_foldername_confirmation_message (5885501832257285329) -->
- <skip />
- <!-- no translation found for delete_files_confirmation_message (8417505791395471802) -->
- <!-- no translation found for delete_folders_confirmation_message (9185648028213507769) -->
- <!-- no translation found for delete_items_confirmation_message (5376214433530243459) -->
+ <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"\"<xliff:g id="NAME">%1$s</xliff:g>\" ಅಳಿಸುವುದೇ?"</string>
+ <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"\"<xliff:g id="NAME">%1$s</xliff:g>\" ಫೋಲ್ಡರ್ ಮತ್ತು ಅದರ ವಿಷಯಗಳನ್ನು ಅಳಿಸುವುದೇ?"</string>
+ <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+ <item quantity="one"> <xliff:g id="COUNT_1">%1$d</xliff:g> ಫೈಲ್ಗಳನ್ನು ಅಳಿಸುವುದೇ?</item>
+ <item quantity="other"> <xliff:g id="COUNT_1">%1$d</xliff:g> ಫೈಲ್ಗಳನ್ನು ಅಳಿಸುವುದೇ?</item>
+ </plurals>
+ <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+ <item quantity="one"> <xliff:g id="COUNT_1">%1$d</xliff:g> ಫೋಲ್ಡರ್ಗಳು ಮತ್ತು ಅವುಗಳ ವಿಷಯಗಳನ್ನು ಅಳಿಸುವುದೇ?</item>
+ <item quantity="other"> <xliff:g id="COUNT_1">%1$d</xliff:g> ಫೋಲ್ಡರ್ಗಳು ಮತ್ತು ಅವುಗಳ ವಿಷಯಗಳನ್ನು ಅಳಿಸುವುದೇ?</item>
+ </plurals>
+ <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+ <item quantity="one"> <xliff:g id="COUNT_1">%1$d</xliff:g> ಐಟಂಗಳನ್ನು ಅಳಿಸುವುದೇ?</item>
+ <item quantity="other"> <xliff:g id="COUNT_1">%1$d</xliff:g> ಐಟಂಗಳನ್ನು ಅಳಿಸುವುದೇ?</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-ko/strings.xml b/packages/DocumentsUI/res/values-ko/strings.xml
index 1b553b5..4d5dcf9 100644
--- a/packages/DocumentsUI/res/values-ko/strings.xml
+++ b/packages/DocumentsUI/res/values-ko/strings.xml
@@ -111,6 +111,7 @@
<string name="rename_error" msgid="4203041674883412606">"문서 이름을 변경하지 못했습니다."</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"일부 파일이 변환되었습니다."</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"<xliff:g id="APPNAME"><b>^1</b></xliff:g>이(가) <xliff:g id="STORAGE"><i>^3</i></xliff:g>에서 <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> 디렉토리에 액세스하도록 허용하시겠습니까?"</string>
+ <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"<xliff:g id="APPNAME"><b>^1</b></xliff:g>이(가) <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> 디렉토리에 액세스하도록 허용하시겠습니까?"</string>
<string name="open_external_dialog_root_request" msgid="8899108702926347720">"<xliff:g id="APPNAME"><b>^1</b></xliff:g>에서 사진, 동영상 등 <xliff:g id="STORAGE"><i>^2</i></xliff:g>의 내 데이터에 액세스하도록 허용하시겠습니까?"</string>
<string name="never_ask_again" msgid="4295278542972859268">"다시 묻지 않음"</string>
<string name="allow" msgid="7225948811296386551">"허용"</string>
@@ -121,7 +122,16 @@
</plurals>
<string name="delete_filename_confirmation_message" msgid="5312817725577537488">"<xliff:g id="NAME">%1$s</xliff:g>을(를) 삭제하시겠습니까?"</string>
<string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"\'<xliff:g id="NAME">%1$s</xliff:g>\' 폴더와 폴더에 포함된 콘텐츠를 삭제하시겠습니까?"</string>
- <!-- no translation found for delete_files_confirmation_message (8417505791395471802) -->
- <!-- no translation found for delete_folders_confirmation_message (9185648028213507769) -->
- <!-- no translation found for delete_items_confirmation_message (5376214433530243459) -->
+ <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+ <item quantity="other">파일 <xliff:g id="COUNT_1">%1$d</xliff:g>개를 삭제하시겠습니까?</item>
+ <item quantity="one">파일 <xliff:g id="COUNT_0">%1$d</xliff:g>개를 삭제하시겠습니까?</item>
+ </plurals>
+ <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+ <item quantity="other">폴더 <xliff:g id="COUNT_1">%1$d</xliff:g>개와 폴더에 포함된 콘텐츠를 삭제하시겠습니까?</item>
+ <item quantity="one">폴더 <xliff:g id="COUNT_0">%1$d</xliff:g>개와 폴더에 포함된 콘텐츠를 삭제하시겠습니까?</item>
+ </plurals>
+ <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+ <item quantity="other">항목 <xliff:g id="COUNT_1">%1$d</xliff:g>개를 삭제하시겠습니까?</item>
+ <item quantity="one">항목 <xliff:g id="COUNT_0">%1$d</xliff:g>개를 삭제하시겠습니까?</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-ky-rKG/strings.xml b/packages/DocumentsUI/res/values-ky-rKG/strings.xml
index f4981b9..1b39039 100644
--- a/packages/DocumentsUI/res/values-ky-rKG/strings.xml
+++ b/packages/DocumentsUI/res/values-ky-rKG/strings.xml
@@ -111,6 +111,7 @@
<string name="rename_error" msgid="4203041674883412606">"Документтин аталышы өзгөртүлбөй калды"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Айрым файлдардын форматы өзгөртүлдү"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> колдонмосуна <xliff:g id="STORAGE"><i>^3</i></xliff:g> түзмөгүндөгү <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> папканы пайдалануу мүмкүнчүлүгү берилсинби?"</string>
+ <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> колдонмосуна <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> каталогун пайдалануу мүмкүнчүлүгү берилсинби?"</string>
<string name="open_external_dialog_root_request" msgid="8899108702926347720">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> колдонмосуна <xliff:g id="STORAGE"><i>^2</i></xliff:g> түзмөгүндөгү дайындарыңыз, сүрөттөрүңүз жана видеолоруңузду пайдалануу мүмкүнчүлүгү берилсинби?"</string>
<string name="never_ask_again" msgid="4295278542972859268">"Экинчи суралбасын"</string>
<string name="allow" msgid="7225948811296386551">"Уруксат берүү"</string>
@@ -119,11 +120,18 @@
<item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> тандалды</item>
<item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> тандалды</item>
</plurals>
- <!-- no translation found for delete_filename_confirmation_message (5312817725577537488) -->
- <skip />
- <!-- no translation found for delete_foldername_confirmation_message (5885501832257285329) -->
- <skip />
- <!-- no translation found for delete_files_confirmation_message (8417505791395471802) -->
- <!-- no translation found for delete_folders_confirmation_message (9185648028213507769) -->
- <!-- no translation found for delete_items_confirmation_message (5376214433530243459) -->
+ <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"\"<xliff:g id="NAME">%1$s</xliff:g>\" жок кылынсынбы?"</string>
+ <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"\"<xliff:g id="NAME">%1$s</xliff:g>\" куржуну мазмуну менен жок кылынсынбы?"</string>
+ <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> файл жок кылынсынбы?</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> файл жок кылынсынбы?</item>
+ </plurals>
+ <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> куржун мазмуну менен жок кылынсынбы?</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> куржун мазмуну менен жок кылынсынбы?</item>
+ </plurals>
+ <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> нерсе жок кылынсынбы?</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> нерсе жок кылынсынбы?</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-lo-rLA/strings.xml b/packages/DocumentsUI/res/values-lo-rLA/strings.xml
index 4203241..a4f381d 100644
--- a/packages/DocumentsUI/res/values-lo-rLA/strings.xml
+++ b/packages/DocumentsUI/res/values-lo-rLA/strings.xml
@@ -111,6 +111,7 @@
<string name="rename_error" msgid="4203041674883412606">"ປ່ຽນຊື່ເອກະສານບໍ່ສຳເລັດ"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"ປ່ຽນແປງບາງໄຟລ໌ແລ້ວ"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"ອະນຸຍາດສິດເຂົ້າເຖິງໃຫ້ <xliff:g id="APPNAME"><b>^1</b></xliff:g> ເພື່ອເຂົ້າໄດເຣກທໍຣີ <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> ຢູ່ <xliff:g id="STORAGE"><i>^3</i></xliff:g> ບໍ?"</string>
+ <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"ອະນຸມັດ <xliff:g id="APPNAME"><b>^1</b></xliff:g> ໃຫ້ເຂົ້າຫາໄດເຣັກທໍຣີ <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> ບໍ?"</string>
<string name="open_external_dialog_root_request" msgid="8899108702926347720">"ອະນຸມັດໃຫ້ <xliff:g id="APPNAME"><b>^1</b></xliff:g> ເຂົ້າເຖິງຂໍ້ມູນຂອງທ່ານ ເຊິ່ງຮວມເຖິງຮູບພາບ ແລະ ວິດີໂອໃນ <xliff:g id="STORAGE"><i>^2</i></xliff:g> ໄດ້ບໍ?"</string>
<string name="never_ask_again" msgid="4295278542972859268">"ບໍ່ຕ້ອງຖາມຄືນ"</string>
<string name="allow" msgid="7225948811296386551">"ອະນຸຍາດ"</string>
@@ -121,7 +122,16 @@
</plurals>
<string name="delete_filename_confirmation_message" msgid="5312817725577537488">"ລຶບ \"<xliff:g id="NAME">%1$s</xliff:g>\" ອອກບໍ?"</string>
<string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"ລຶບໂຟນເດີ \"<xliff:g id="NAME">%1$s</xliff:g>\" ແລະ ເນື້ອຫາທັງໝົດຂອງມັນອອກບໍ?"</string>
- <!-- no translation found for delete_files_confirmation_message (8417505791395471802) -->
- <!-- no translation found for delete_folders_confirmation_message (9185648028213507769) -->
- <!-- no translation found for delete_items_confirmation_message (5376214433530243459) -->
+ <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+ <item quantity="other">ລຶບ <xliff:g id="COUNT_1">%1$d</xliff:g> ໄຟລ໌ອອກບໍ?</item>
+ <item quantity="one">ລຶບ <xliff:g id="COUNT_0">%1$d</xliff:g> ໄຟລ໌ອອກບໍ?</item>
+ </plurals>
+ <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+ <item quantity="other">ລຶບ <xliff:g id="COUNT_1">%1$d</xliff:g> ໂຟນເດີ ແລະ ເນື້ອຫາຂອງມັນອອກບໍ?</item>
+ <item quantity="one">ລຶບ <xliff:g id="COUNT_0">%1$d</xliff:g> ໂຟນເດີ ແລະ ເນື້ອຫາຂອງມັນອອກບໍ?</item>
+ </plurals>
+ <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+ <item quantity="other">ລຶບ <xliff:g id="COUNT_1">%1$d</xliff:g> ລາຍການອອກບໍ?</item>
+ <item quantity="one">ລຶບ <xliff:g id="COUNT_0">%1$d</xliff:g> ລາຍການອອກບໍ?</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-lt/strings.xml b/packages/DocumentsUI/res/values-lt/strings.xml
index 5114854..2e0df93 100644
--- a/packages/DocumentsUI/res/values-lt/strings.xml
+++ b/packages/DocumentsUI/res/values-lt/strings.xml
@@ -125,6 +125,7 @@
<string name="rename_error" msgid="4203041674883412606">"Nepavyko pervardyti dokumento"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Kai kurie failai buvo konvertuoti"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"Suteikti „<xliff:g id="APPNAME"><b>^1</b></xliff:g>“ prieigą prie katalogo „<xliff:g id="DIRECTORY"><i>^2</i></xliff:g>“ <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
+ <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Suteikti „<xliff:g id="APPNAME"><b>^1</b></xliff:g>“ prieigą prie katalogo „<xliff:g id="DIRECTORY"><i>^2</i></xliff:g>“?"</string>
<string name="open_external_dialog_root_request" msgid="8899108702926347720">"Suteikti programai „<xliff:g id="APPNAME"><b>^1</b></xliff:g>“ prieigą prie duomenų, įskaitant nuotraukas ir vaizdo įrašus, <xliff:g id="STORAGE"><i>^2</i></xliff:g>?"</string>
<string name="never_ask_again" msgid="4295278542972859268">"Daugiau neklausti"</string>
<string name="allow" msgid="7225948811296386551">"Leisti"</string>
@@ -137,7 +138,22 @@
</plurals>
<string name="delete_filename_confirmation_message" msgid="5312817725577537488">"Ištrinti „<xliff:g id="NAME">%1$s</xliff:g>“?"</string>
<string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"Ištrinti aplanką „<xliff:g id="NAME">%1$s</xliff:g>“ ir jo turinį?"</string>
- <!-- no translation found for delete_files_confirmation_message (8417505791395471802) -->
- <!-- no translation found for delete_folders_confirmation_message (9185648028213507769) -->
- <!-- no translation found for delete_items_confirmation_message (5376214433530243459) -->
+ <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+ <item quantity="one">Ištrinti <xliff:g id="COUNT_1">%1$d</xliff:g> failą?</item>
+ <item quantity="few">Ištrinti <xliff:g id="COUNT_1">%1$d</xliff:g> failus?</item>
+ <item quantity="many">Ištrinti <xliff:g id="COUNT_1">%1$d</xliff:g> failo?</item>
+ <item quantity="other">Ištrinti <xliff:g id="COUNT_1">%1$d</xliff:g> failų?</item>
+ </plurals>
+ <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+ <item quantity="one">Ištrinti <xliff:g id="COUNT_1">%1$d</xliff:g> aplanką ir jų turinį?</item>
+ <item quantity="few">Ištrinti <xliff:g id="COUNT_1">%1$d</xliff:g> aplankus ir jų turinį?</item>
+ <item quantity="many">Ištrinti <xliff:g id="COUNT_1">%1$d</xliff:g> aplanko ir jų turinį?</item>
+ <item quantity="other">Ištrinti <xliff:g id="COUNT_1">%1$d</xliff:g> aplankų ir jų turinį?</item>
+ </plurals>
+ <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+ <item quantity="one">Ištrinti <xliff:g id="COUNT_1">%1$d</xliff:g> elementą?</item>
+ <item quantity="few">Ištrinti <xliff:g id="COUNT_1">%1$d</xliff:g> elementus?</item>
+ <item quantity="many">Ištrinti <xliff:g id="COUNT_1">%1$d</xliff:g> elemento?</item>
+ <item quantity="other">Ištrinti <xliff:g id="COUNT_1">%1$d</xliff:g> elementų?</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-lv/strings.xml b/packages/DocumentsUI/res/values-lv/strings.xml
index 8ee161d..fb81aa0 100644
--- a/packages/DocumentsUI/res/values-lv/strings.xml
+++ b/packages/DocumentsUI/res/values-lv/strings.xml
@@ -118,6 +118,7 @@
<string name="rename_error" msgid="4203041674883412606">"Neizdevās pārdēvēt dokumentu"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Daži faili tika pārveidoti."</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"Vai atļaut lietotnei <xliff:g id="APPNAME"><b>^1</b></xliff:g> piekļūt direktorijam <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> šajā krātuvē: <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
+ <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Vai piešķirt lietotnei <xliff:g id="APPNAME"><b>^1</b></xliff:g> piekļuvi direktorijam <xliff:g id="DIRECTORY"><i>^2</i></xliff:g>?"</string>
<string name="open_external_dialog_root_request" msgid="8899108702926347720">"Vai atļaut lietotnei <xliff:g id="APPNAME"><b>^1</b></xliff:g> piekļūt jūsu datiem, tostarp fotoattēliem un videoklipiem, šajā krātuvē: <xliff:g id="STORAGE"><i>^2</i></xliff:g>?"</string>
<string name="never_ask_again" msgid="4295278542972859268">"Turpmāk vairs nejautāt"</string>
<string name="allow" msgid="7225948811296386551">"Atļaut"</string>
@@ -129,7 +130,19 @@
</plurals>
<string name="delete_filename_confirmation_message" msgid="5312817725577537488">"Vai izdzēst failu “<xliff:g id="NAME">%1$s</xliff:g>”?"</string>
<string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"Vai izdzēst mapi “<xliff:g id="NAME">%1$s</xliff:g>” un tās saturu?"</string>
- <!-- no translation found for delete_files_confirmation_message (8417505791395471802) -->
- <!-- no translation found for delete_folders_confirmation_message (9185648028213507769) -->
- <!-- no translation found for delete_items_confirmation_message (5376214433530243459) -->
+ <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+ <item quantity="zero">Vai izdzēst <xliff:g id="COUNT_1">%1$d</xliff:g> failus?</item>
+ <item quantity="one">Vai izdzēst <xliff:g id="COUNT_1">%1$d</xliff:g> failu?</item>
+ <item quantity="other">Vai izdzēst <xliff:g id="COUNT_1">%1$d</xliff:g> failus?</item>
+ </plurals>
+ <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+ <item quantity="zero">Vai izdzēst <xliff:g id="COUNT_1">%1$d</xliff:g> mapes un to saturu?</item>
+ <item quantity="one">Vai izdzēst <xliff:g id="COUNT_1">%1$d</xliff:g> mapi un to saturu?</item>
+ <item quantity="other">Vai izdzēst <xliff:g id="COUNT_1">%1$d</xliff:g> mapes un to saturu?</item>
+ </plurals>
+ <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+ <item quantity="zero">Vai izdzēst <xliff:g id="COUNT_1">%1$d</xliff:g> vienumus?</item>
+ <item quantity="one">Vai izdzēst <xliff:g id="COUNT_1">%1$d</xliff:g> vienumu?</item>
+ <item quantity="other">Vai izdzēst <xliff:g id="COUNT_1">%1$d</xliff:g> vienumus?</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-mk-rMK/strings.xml b/packages/DocumentsUI/res/values-mk-rMK/strings.xml
index 5fb64f1..ad428a0 100644
--- a/packages/DocumentsUI/res/values-mk-rMK/strings.xml
+++ b/packages/DocumentsUI/res/values-mk-rMK/strings.xml
@@ -111,6 +111,7 @@
<string name="rename_error" msgid="4203041674883412606">"Не успеа да се преименува документот"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Некои датотеки беа конвертирани"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"Овозможете пристап на <xliff:g id="APPNAME"><b>^1</b></xliff:g> до директориумот <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> на <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
+ <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Овозможете пристап на <xliff:g id="APPNAME"><b>^1</b></xliff:g> до директориумот <xliff:g id="DIRECTORY"><i>^2</i></xliff:g>?"</string>
<string name="open_external_dialog_root_request" msgid="8899108702926347720">"Да се овозможи пристап на <xliff:g id="APPNAME"><b>^1</b></xliff:g> до вашите податоци, вклучувајќи фотографии и видеа, на <xliff:g id="STORAGE"><i>^2</i></xliff:g>?"</string>
<string name="never_ask_again" msgid="4295278542972859268">"Не прашувај повторно"</string>
<string name="allow" msgid="7225948811296386551">"Дозволи"</string>
@@ -121,7 +122,16 @@
</plurals>
<string name="delete_filename_confirmation_message" msgid="5312817725577537488">"Да се избрише „<xliff:g id="NAME">%1$s</xliff:g>“?"</string>
<string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"Да се избрише папката „<xliff:g id="NAME">%1$s</xliff:g>“ и нејзините содржини?"</string>
- <!-- no translation found for delete_files_confirmation_message (8417505791395471802) -->
- <!-- no translation found for delete_folders_confirmation_message (9185648028213507769) -->
- <!-- no translation found for delete_items_confirmation_message (5376214433530243459) -->
+ <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+ <item quantity="one">Да се избрише <xliff:g id="COUNT_1">%1$d</xliff:g> датотека?</item>
+ <item quantity="other">Да се избришат <xliff:g id="COUNT_1">%1$d</xliff:g> датотеки?</item>
+ </plurals>
+ <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+ <item quantity="one">Да се избрише <xliff:g id="COUNT_1">%1$d</xliff:g> папка и нивните содржини?</item>
+ <item quantity="other">Да се избришат <xliff:g id="COUNT_1">%1$d</xliff:g> папки и нивните содржини?</item>
+ </plurals>
+ <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+ <item quantity="one">Да се избрише <xliff:g id="COUNT_1">%1$d</xliff:g> ставка?</item>
+ <item quantity="other">Да се избришат <xliff:g id="COUNT_1">%1$d</xliff:g> ставки?</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-ml-rIN/strings.xml b/packages/DocumentsUI/res/values-ml-rIN/strings.xml
index afb26a0..5a16512 100644
--- a/packages/DocumentsUI/res/values-ml-rIN/strings.xml
+++ b/packages/DocumentsUI/res/values-ml-rIN/strings.xml
@@ -111,6 +111,7 @@
<string name="rename_error" msgid="4203041674883412606">"ഡോക്യുമെന്റിന്റെ പേരുമാറ്റുന്നത് പരാജയപ്പെട്ടു"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"ചില ഫയലുകൾ പരിവർത്തനം ചെയ്യപ്പെട്ടു"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"<xliff:g id="STORAGE"><i>^3</i></xliff:g> സ്റ്റോറേജിലെ <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> എന്ന ഡയറക്റ്ററിയിലേക്ക് <xliff:g id="APPNAME"><b>^1</b></xliff:g> ആപ്പിന് ആക്സസ് അനുവദിക്കണോ?"</string>
+ <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"<xliff:g id="DIRECTORY"><i>^2</i></xliff:g> എന്ന ഡയറക്ടറിയിലേക്ക് <xliff:g id="APPNAME"><b>^1</b></xliff:g> ആപ്പിന് ആക്സസ് അനുവദിക്കണോ?"</string>
<string name="open_external_dialog_root_request" msgid="8899108702926347720">"<xliff:g id="STORAGE"><i>^2</i></xliff:g> സ്റ്റോറേജിലെ ഫോട്ടോകളും വീഡിയോകളും ഉൾപ്പെടെ, നിങ്ങളുടെ ഡാറ്റയിലേക്ക് <xliff:g id="APPNAME"><b>^1</b></xliff:g> ആപ്പിന് ആക്സസ്സ് അനുവദിക്കണോ?"</string>
<string name="never_ask_again" msgid="4295278542972859268">"വീണ്ടും ആവശ്യപ്പെടരുത്"</string>
<string name="allow" msgid="7225948811296386551">"അനുവദിക്കുക"</string>
@@ -119,11 +120,18 @@
<item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> തിരഞ്ഞെടുത്തു</item>
<item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> തിരഞ്ഞെടുത്തു</item>
</plurals>
- <!-- no translation found for delete_filename_confirmation_message (5312817725577537488) -->
- <skip />
- <!-- no translation found for delete_foldername_confirmation_message (5885501832257285329) -->
- <skip />
- <!-- no translation found for delete_files_confirmation_message (8417505791395471802) -->
- <!-- no translation found for delete_folders_confirmation_message (9185648028213507769) -->
- <!-- no translation found for delete_items_confirmation_message (5376214433530243459) -->
+ <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"\"<xliff:g id="NAME">%1$s</xliff:g>\" ഇല്ലാതാക്കണോ?"</string>
+ <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"\"<xliff:g id="NAME">%1$s</xliff:g>\" എന്ന ഫോൾഡറും അതിലെ ഉള്ളടങ്ങളും ഇല്ലാതാക്കണോ?"</string>
+ <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ഫയലുകൾ ഇല്ലാതാക്കണോ?</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> ഫയൽ ഇല്ലാതാക്കണോ?</item>
+ </plurals>
+ <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ഫോൾഡറുകളും അവയിലെ ഉള്ളടക്കങ്ങളും ഇല്ലാതാക്കണോ?</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> ഫോൾഡറും അതിലെ ഉള്ളടക്കങ്ങളും ഇല്ലാതാക്കണോ?</item>
+ </plurals>
+ <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ഇനങ്ങൾ ഇല്ലാതാക്കണോ?</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> ഇനം ഇല്ലാതാക്കണോ?</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-mn-rMN/strings.xml b/packages/DocumentsUI/res/values-mn-rMN/strings.xml
index 2890908..cf2c2d4 100644
--- a/packages/DocumentsUI/res/values-mn-rMN/strings.xml
+++ b/packages/DocumentsUI/res/values-mn-rMN/strings.xml
@@ -111,6 +111,7 @@
<string name="rename_error" msgid="4203041674883412606">"Баримт бичгийн нэрийн өөрчилж чадсангүй"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Зарим файлыг хөрвүүлсэн"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"<xliff:g id="STORAGE"><i>^3</i></xliff:g>-д байгаа <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> лавлагаанд хандахыг <xliff:g id="APPNAME"><b>^1</b></xliff:g>-д зөвшөөрөх үү?"</string>
+ <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"<xliff:g id="DIRECTORY"><i>^2</i></xliff:g> лавлагаанд хандах эрхийг <xliff:g id="APPNAME"><b>^1</b></xliff:g>-д олгох уу?"</string>
<string name="open_external_dialog_root_request" msgid="8899108702926347720">"<xliff:g id="STORAGE"><i>^2</i></xliff:g>-д байгаа зураг, видео гэх мэт таны өгөгдөлд <xliff:g id="APPNAME"><b>^1</b></xliff:g> хандахыг зөвшөөрөх үү?"</string>
<string name="never_ask_again" msgid="4295278542972859268">"Дахин бүү асуу"</string>
<string name="allow" msgid="7225948811296386551">"Зөвшөөрөх"</string>
@@ -121,7 +122,16 @@
</plurals>
<string name="delete_filename_confirmation_message" msgid="5312817725577537488">"\"<xliff:g id="NAME">%1$s</xliff:g>\"-г устгах уу?"</string>
<string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"\"<xliff:g id="NAME">%1$s</xliff:g>\" фолдер болон үүний агуулгыг устгах уу?"</string>
- <!-- no translation found for delete_files_confirmation_message (8417505791395471802) -->
- <!-- no translation found for delete_folders_confirmation_message (9185648028213507769) -->
- <!-- no translation found for delete_items_confirmation_message (5376214433530243459) -->
+ <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+ <item quantity="other"> <xliff:g id="COUNT_1">%1$d</xliff:g> файлыг устгах уу?</item>
+ <item quantity="one"> <xliff:g id="COUNT_0">%1$d</xliff:g> файлыг устгах уу?</item>
+ </plurals>
+ <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+ <item quantity="other"> <xliff:g id="COUNT_1">%1$d</xliff:g> фолдер болон агуулгуудыг нь устгах уу?</item>
+ <item quantity="one"> <xliff:g id="COUNT_0">%1$d</xliff:g> фолдер болон агуулгыг нь устгах уу?</item>
+ </plurals>
+ <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+ <item quantity="other"> <xliff:g id="COUNT_1">%1$d</xliff:g> зүйлийг устгах уу?</item>
+ <item quantity="one"> <xliff:g id="COUNT_0">%1$d</xliff:g> зүйлийг устгах уу?</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-mr-rIN/strings.xml b/packages/DocumentsUI/res/values-mr-rIN/strings.xml
index e850b26..09dd133 100644
--- a/packages/DocumentsUI/res/values-mr-rIN/strings.xml
+++ b/packages/DocumentsUI/res/values-mr-rIN/strings.xml
@@ -111,6 +111,7 @@
<string name="rename_error" msgid="4203041674883412606">"दस्तऐवज पुनर्नामित करण्यात अयशस्वी झाले"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"काही फायली रूपांतरित केल्या होत्या"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"<xliff:g id="STORAGE"><i>^3</i></xliff:g> वर <xliff:g id="APPNAME"><b>^1</b></xliff:g> ला <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> निर्देशिकेवर प्रवेशाची मंजूरी द्यायची?"</string>
+ <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> ला <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> निर्देशिकमध्ये प्रवेश मंजूर करायचा?"</string>
<string name="open_external_dialog_root_request" msgid="8899108702926347720">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> ला <xliff:g id="STORAGE"><i>^2</i></xliff:g> वर फोटो आणि व्हिडिओंसह, आपल्या डेटामध्ये प्रवेश करण्याची मंजूरी द्यायची?"</string>
<string name="never_ask_again" msgid="4295278542972859268">"पुन्हा विचारू नका"</string>
<string name="allow" msgid="7225948811296386551">"अनुमती द्या"</string>
@@ -119,11 +120,18 @@
<item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> निवडला</item>
<item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> निवडले</item>
</plurals>
- <!-- no translation found for delete_filename_confirmation_message (5312817725577537488) -->
- <skip />
- <!-- no translation found for delete_foldername_confirmation_message (5885501832257285329) -->
- <skip />
- <!-- no translation found for delete_files_confirmation_message (8417505791395471802) -->
- <!-- no translation found for delete_folders_confirmation_message (9185648028213507769) -->
- <!-- no translation found for delete_items_confirmation_message (5376214433530243459) -->
+ <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"\"<xliff:g id="NAME">%1$s</xliff:g>\" हटवायची?"</string>
+ <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"\"<xliff:g id="NAME">%1$s</xliff:g>\" फोल्डर आणि त्यामधील सामग्री हटवायची?"</string>
+ <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+ <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> फाईल हटवायची?</item>
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> फायली हटवायच्या?</item>
+ </plurals>
+ <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+ <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> फोल्डर आणि त्यामधील सामग्री हटवायची?</item>
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> फोल्डर आणि त्यामधील सामग्री हटवायची?</item>
+ </plurals>
+ <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+ <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> आयटम हटवायचा?</item>
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> आयटम हटवायचे?</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-ms-rMY/strings.xml b/packages/DocumentsUI/res/values-ms-rMY/strings.xml
index 374cbb0..9eb3d49 100644
--- a/packages/DocumentsUI/res/values-ms-rMY/strings.xml
+++ b/packages/DocumentsUI/res/values-ms-rMY/strings.xml
@@ -111,6 +111,7 @@
<string name="rename_error" msgid="4203041674883412606">"Gagal menamakan semula dokumen"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Sesetengah fail telah ditukarkan"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"Beri <xliff:g id="APPNAME"><b>^1</b></xliff:g> akses kepada direktori <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> di <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
+ <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Beri <xliff:g id="APPNAME"><b>^1</b></xliff:g> akses kepada direktori <xliff:g id="DIRECTORY"><i>^2</i></xliff:g>?"</string>
<string name="open_external_dialog_root_request" msgid="8899108702926347720">"Beri <xliff:g id="APPNAME"><b>^1</b></xliff:g> akses kepada data anda, termasuk foto dan video pada <xliff:g id="STORAGE"><i>^2</i></xliff:g>?"</string>
<string name="never_ask_again" msgid="4295278542972859268">"Jangan tanya lagi"</string>
<string name="allow" msgid="7225948811296386551">"Benarkan"</string>
@@ -121,7 +122,16 @@
</plurals>
<string name="delete_filename_confirmation_message" msgid="5312817725577537488">"Padamkan \"<xliff:g id="NAME">%1$s</xliff:g>\"?"</string>
<string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"Padamkan folder \"<xliff:g id="NAME">%1$s</xliff:g>\" dan kandungannya?"</string>
- <!-- no translation found for delete_files_confirmation_message (8417505791395471802) -->
- <!-- no translation found for delete_folders_confirmation_message (9185648028213507769) -->
- <!-- no translation found for delete_items_confirmation_message (5376214433530243459) -->
+ <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+ <item quantity="other">Padamkan <xliff:g id="COUNT_1">%1$d</xliff:g> fail?</item>
+ <item quantity="one">Padamkan <xliff:g id="COUNT_0">%1$d</xliff:g> fail?</item>
+ </plurals>
+ <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+ <item quantity="other">Padamkan <xliff:g id="COUNT_1">%1$d</xliff:g> folder dan kandungannya?</item>
+ <item quantity="one">Padamkan <xliff:g id="COUNT_0">%1$d</xliff:g> folder dan kandungannya?</item>
+ </plurals>
+ <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+ <item quantity="other">Padamkan <xliff:g id="COUNT_1">%1$d</xliff:g> item?</item>
+ <item quantity="one">Padamkan <xliff:g id="COUNT_0">%1$d</xliff:g> item?</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-my-rMM/strings.xml b/packages/DocumentsUI/res/values-my-rMM/strings.xml
index 80afcfb..7c637c4 100644
--- a/packages/DocumentsUI/res/values-my-rMM/strings.xml
+++ b/packages/DocumentsUI/res/values-my-rMM/strings.xml
@@ -111,6 +111,7 @@
<string name="rename_error" msgid="4203041674883412606">"စာရွက်စာတမ်းကို အမည်ပြောင်းခြင်း မအောင်မြင်ပါ"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"အချို့ဖိုင်များကို ပြောင်းလဲထားသည်"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> ကို <xliff:g id="STORAGE"><i>^3</i></xliff:g> ရှိ <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> လမ်းညွှန်အား အသုံးပြုခွင့်ပေးမလား။"</string>
+ <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> အား <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> စာရင်းကို အသုံးပြုခွင့်ပေးမလား။"</string>
<string name="open_external_dialog_root_request" msgid="8899108702926347720">"<xliff:g id="STORAGE"><i>^2</i></xliff:g> ရှိဓာတ်ပုံများနှင့် ဗီဒီယိုများအပါအဝင် သင့်ဒေတာများကို <xliff:g id="APPNAME"><b>^1</b></xliff:g> အားအသုံးပြုခွင့်ပေးမလား။"</string>
<string name="never_ask_again" msgid="4295278542972859268">"နောက်ထပ်မမေးပါနှင့်"</string>
<string name="allow" msgid="7225948811296386551">"ခွင့်ပြုသည်"</string>
@@ -121,7 +122,16 @@
</plurals>
<string name="delete_filename_confirmation_message" msgid="5312817725577537488">"\"<xliff:g id="NAME">%1$s</xliff:g>\" ကိုဖျက်မလား။"</string>
<string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"\"<xliff:g id="NAME">%1$s</xliff:g>\" ဖိုင်တွဲနှင့် ၎င်းတွင်ပါဝင်သည့် အကြောင်းအရာများကို ဖျက်မလား။"</string>
- <!-- no translation found for delete_files_confirmation_message (8417505791395471802) -->
- <!-- no translation found for delete_folders_confirmation_message (9185648028213507769) -->
- <!-- no translation found for delete_items_confirmation_message (5376214433530243459) -->
+ <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+ <item quantity="other">ဖိုင် <xliff:g id="COUNT_1">%1$d</xliff:g> ခုကိုဖျက်မလား။</item>
+ <item quantity="one">ဖိုင် <xliff:g id="COUNT_0">%1$d</xliff:g> ခုကိုဖျက်မလား။</item>
+ </plurals>
+ <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+ <item quantity="other">ဖိုင်တွဲ <xliff:g id="COUNT_1">%1$d</xliff:g> ခုနှင့် ၎င်း၏အကြောင်းအရာများကို ဖျက်မလား။</item>
+ <item quantity="one">ဖိုင်တွဲ <xliff:g id="COUNT_0">%1$d</xliff:g> ခုနှင့် ၎င်း၏အကြောင်းအရာများကို ဖျက်မလား။</item>
+ </plurals>
+ <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+ <item quantity="other">အကြောင်းအရာ <xliff:g id="COUNT_1">%1$d</xliff:g> ခုကိုဖျက်မလား။</item>
+ <item quantity="one">အကြောင်းအရာ <xliff:g id="COUNT_0">%1$d</xliff:g> ခုကိုဖျက်မလား။</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-nb/strings.xml b/packages/DocumentsUI/res/values-nb/strings.xml
index 8349a13..3c344eb 100644
--- a/packages/DocumentsUI/res/values-nb/strings.xml
+++ b/packages/DocumentsUI/res/values-nb/strings.xml
@@ -111,6 +111,7 @@
<string name="rename_error" msgid="4203041674883412606">"Kunne ikke gi dokumentet nytt navn"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Noen filer er konvertert"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"Vil du gi <xliff:g id="APPNAME"><b>^1</b></xliff:g> tilgang til <xliff:g id="DIRECTORY"><i>^2</i></xliff:g>-katalogen på <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
+ <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Vil du gi <xliff:g id="APPNAME"><b>^1</b></xliff:g> tilgang til <xliff:g id="DIRECTORY"><i>^2</i></xliff:g>-katalogen?"</string>
<string name="open_external_dialog_root_request" msgid="8899108702926347720">"Vil du gi <xliff:g id="APPNAME"><b>^1</b></xliff:g> tilgang til dataene dine – inkludert bilder og videoer – på <xliff:g id="STORAGE"><i>^2</i></xliff:g>?"</string>
<string name="never_ask_again" msgid="4295278542972859268">"Ikke spør igjen"</string>
<string name="allow" msgid="7225948811296386551">"Tillat"</string>
@@ -121,7 +122,16 @@
</plurals>
<string name="delete_filename_confirmation_message" msgid="5312817725577537488">"Vil du slette «<xliff:g id="NAME">%1$s</xliff:g>»?"</string>
<string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"Vil du slette «<xliff:g id="NAME">%1$s</xliff:g>»-mappen og innholdet i den?"</string>
- <!-- no translation found for delete_files_confirmation_message (8417505791395471802) -->
- <!-- no translation found for delete_folders_confirmation_message (9185648028213507769) -->
- <!-- no translation found for delete_items_confirmation_message (5376214433530243459) -->
+ <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+ <item quantity="other">Vil du slette <xliff:g id="COUNT_1">%1$d</xliff:g> filer?</item>
+ <item quantity="one">Vil du slette <xliff:g id="COUNT_0">%1$d</xliff:g> fil?</item>
+ </plurals>
+ <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+ <item quantity="other">Vil du slette <xliff:g id="COUNT_1">%1$d</xliff:g> mapper og innholdet i dem?</item>
+ <item quantity="one">Vil du slette <xliff:g id="COUNT_0">%1$d</xliff:g> mappe og innholdet i den?</item>
+ </plurals>
+ <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+ <item quantity="other">Vil du slette <xliff:g id="COUNT_1">%1$d</xliff:g> elementer?</item>
+ <item quantity="one">Vil du slette <xliff:g id="COUNT_0">%1$d</xliff:g> element?</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-ne-rNP/strings.xml b/packages/DocumentsUI/res/values-ne-rNP/strings.xml
index a110742..9fef037 100644
--- a/packages/DocumentsUI/res/values-ne-rNP/strings.xml
+++ b/packages/DocumentsUI/res/values-ne-rNP/strings.xml
@@ -111,6 +111,7 @@
<string name="rename_error" msgid="4203041674883412606">"कागजात पुन: नामाकरण गर्न असफल भयो"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"केही फाइलहरू परिवर्तन गरिएका थिए"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> लाई <xliff:g id="STORAGE"><i>^3</i></xliff:g> मा भएको <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> निर्देशिकामा पहुँच गर्न अनुमति दिने हो?"</string>
+ <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> लाई <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> निर्देशिकामाथि पहुँच गर्न अनुमति प्रदान गर्ने हो?"</string>
<string name="open_external_dialog_root_request" msgid="8899108702926347720">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> लाई <xliff:g id="STORAGE"><i>^2</i></xliff:g> मा भएका तस्बिर र भिडियोहरू लगायत तपाईँको डेटामा पहुँच गर्नका लागि अनुमति दिने हो?"</string>
<string name="never_ask_again" msgid="4295278542972859268">"फेरि नसोध्नुहोस्"</string>
<string name="allow" msgid="7225948811296386551">"अनुमति दिनुहोस्"</string>
@@ -119,11 +120,18 @@
<item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> लाई चयन गरियो</item>
<item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> लाई चयन गरियो</item>
</plurals>
- <!-- no translation found for delete_filename_confirmation_message (5312817725577537488) -->
- <skip />
- <!-- no translation found for delete_foldername_confirmation_message (5885501832257285329) -->
- <skip />
- <!-- no translation found for delete_files_confirmation_message (8417505791395471802) -->
- <!-- no translation found for delete_folders_confirmation_message (9185648028213507769) -->
- <!-- no translation found for delete_items_confirmation_message (5376214433530243459) -->
+ <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"\"<xliff:g id="NAME">%1$s</xliff:g>\" लाई मेट्ने हो?"</string>
+ <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"फोल्डर \"<xliff:g id="NAME">%1$s</xliff:g>\" र यसका सामग्रीहरूलाई मेट्ने हो?"</string>
+ <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> फाइलहरूलाई मेट्ने हो?</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> फाइललाई मेट्ने हो?</item>
+ </plurals>
+ <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> फोल्डरहरू र तिनीहरूका सामग्रीहरूलाई मेट्ने हो?</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> फोल्डर र यसका सामग्रीहरूलाई मेट्ने हो?</item>
+ </plurals>
+ <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> वस्तुहरूलाई मेट्ने हो?</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> वस्तुलाई मेट्ने हो?</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-nl/strings.xml b/packages/DocumentsUI/res/values-nl/strings.xml
index 27796cf..c5b9d76 100644
--- a/packages/DocumentsUI/res/values-nl/strings.xml
+++ b/packages/DocumentsUI/res/values-nl/strings.xml
@@ -111,6 +111,7 @@
<string name="rename_error" msgid="4203041674883412606">"Kan naam van document niet wijzigen"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Sommige bestanden zijn geconverteerd"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> toegang verlenen tot de map <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> op <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
+ <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> toegang verlenen tot de map <xliff:g id="DIRECTORY"><i>^2</i></xliff:g>?"</string>
<string name="open_external_dialog_root_request" msgid="8899108702926347720">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> toegang verlenen tot je gegevens, waaronder foto\'s en video\'s, op <xliff:g id="STORAGE"><i>^2</i></xliff:g>?"</string>
<string name="never_ask_again" msgid="4295278542972859268">"Niet meer vragen"</string>
<string name="allow" msgid="7225948811296386551">"Toestaan"</string>
@@ -121,7 +122,16 @@
</plurals>
<string name="delete_filename_confirmation_message" msgid="5312817725577537488">"<xliff:g id="NAME">%1$s</xliff:g> verwijderen?"</string>
<string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"Map <xliff:g id="NAME">%1$s</xliff:g> en de bijbehorende inhoud verwijderen?"</string>
- <!-- no translation found for delete_files_confirmation_message (8417505791395471802) -->
- <!-- no translation found for delete_folders_confirmation_message (9185648028213507769) -->
- <!-- no translation found for delete_items_confirmation_message (5376214433530243459) -->
+ <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> bestanden verwijderen?</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> bestand verwijderen?</item>
+ </plurals>
+ <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> mappen en de bijbehorende inhoud verwijderen?</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> map en de bijbehorende inhoud verwijderen?</item>
+ </plurals>
+ <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> items verwijderen?</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> item verwijderen?</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-pa-rIN/strings.xml b/packages/DocumentsUI/res/values-pa-rIN/strings.xml
index 503bc0d..7d5e14a 100644
--- a/packages/DocumentsUI/res/values-pa-rIN/strings.xml
+++ b/packages/DocumentsUI/res/values-pa-rIN/strings.xml
@@ -111,6 +111,7 @@
<string name="rename_error" msgid="4203041674883412606">"ਦਸਤਾਵੇਜ਼ ਦਾ ਮੁੜ-ਨਾਮਕਰਨ ਕਰਨਾ ਅਸਫਲ ਰਿਹਾ"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"ਕੁਝ ਫ਼ਾਈਲਾਂ ਤਬਦੀਲ ਕੀਤੀਆਂ ਗਈਆਂ ਸਨ"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"ਕੀ <xliff:g id="APPNAME"><b>^1</b></xliff:g> ਨੂੰ <xliff:g id="STORAGE"><i>^3</i></xliff:g> \'ਤੇ <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> ਡਾਇਰੈਕਟਰੀ \'ਤੇ ਪਹੁੰਚ ਦੇਣੀ ਹੈ?"</string>
+ <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"ਕੀ <xliff:g id="APPNAME"><b>^1</b></xliff:g> ਨੂੰ <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> ਡਾਇਰੈਕਟਰੀ \'ਤੇ ਪਹੁੰਚ ਦੇਣੀ ਹੈ?"</string>
<string name="open_external_dialog_root_request" msgid="8899108702926347720">"ਕੀ <xliff:g id="APPNAME"><b>^1</b></xliff:g> ਨੂੰ <xliff:g id="STORAGE"><i>^2</i></xliff:g> \'ਤੇ ਫੋਟੋਆਂ ਅਤੇ ਵੀਡੀਓ ਸਮੇਤ, ਤੁਹਾਡੇ ਡੈਟੇ \'ਤੇ ਪਹੁੰਚ ਦੇਣੀ ਹੈ?"</string>
<string name="never_ask_again" msgid="4295278542972859268">"ਦੁਬਾਰਾ ਨਾ ਪੁੱਛੋ"</string>
<string name="allow" msgid="7225948811296386551">"ਆਗਿਆ ਦਿਓ"</string>
@@ -119,11 +120,18 @@
<item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> ਚੁਣੀ ਗਈ</item>
<item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ਚੁਣੀਆਂ ਗਈਆਂ</item>
</plurals>
- <!-- no translation found for delete_filename_confirmation_message (5312817725577537488) -->
- <skip />
- <!-- no translation found for delete_foldername_confirmation_message (5885501832257285329) -->
- <skip />
- <!-- no translation found for delete_files_confirmation_message (8417505791395471802) -->
- <!-- no translation found for delete_folders_confirmation_message (9185648028213507769) -->
- <!-- no translation found for delete_items_confirmation_message (5376214433530243459) -->
+ <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"ਕੀ \"<xliff:g id="NAME">%1$s</xliff:g>\" ਨੂੰ ਮਿਟਾਉਣਾ ਹੈ?"</string>
+ <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"ਫੋਲਡਰ \"<xliff:g id="NAME">%1$s</xliff:g>\" ਅਤੇ ਉਸ ਦੀਆਂ ਸਮੱਗਰੀਆਂ ਨੂੰ ਮਿਟਾਉਣਾ ਹੈ?"</string>
+ <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+ <item quantity="one">ਕੀ <xliff:g id="COUNT_1">%1$d</xliff:g> ਫ਼ਾਈਲਾਂ ਨੂੰ ਮਿਟਾਉਣਾ ਹੈ?</item>
+ <item quantity="other">ਕੀ <xliff:g id="COUNT_1">%1$d</xliff:g> ਫ਼ਾਈਲਾਂ ਨੂੰ ਮਿਟਾਉਣਾ ਹੈ?</item>
+ </plurals>
+ <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+ <item quantity="one">ਕੀ <xliff:g id="COUNT_1">%1$d</xliff:g> ਫੋਲਡਰਾਂ ਅਤੇ ਉਹਨਾਂ ਦੀਆਂ ਸਮੱਗਰੀਆਂ ਨੂੰ ਮਿਟਾਉਣਾ ਹੈ?</item>
+ <item quantity="other">ਕੀ <xliff:g id="COUNT_1">%1$d</xliff:g> ਫੋਲਡਰਾਂ ਅਤੇ ਉਹਨਾਂ ਦੀਆਂ ਸਮੱਗਰੀਆਂ ਨੂੰ ਮਿਟਾਉਣਾ ਹੈ?</item>
+ </plurals>
+ <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+ <item quantity="one">ਕੀ <xliff:g id="COUNT_1">%1$d</xliff:g> ਆਈਟਮਾਂ ਨੂੰ ਮਿਟਾਉਣਾ ਹੈ?</item>
+ <item quantity="other">ਕੀ <xliff:g id="COUNT_1">%1$d</xliff:g> ਆਈਟਮਾਂ ਨੂੰ ਮਿਟਾਉਣਾ ਹੈ?</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-pl/strings.xml b/packages/DocumentsUI/res/values-pl/strings.xml
index 7f0b274..ca007d7 100644
--- a/packages/DocumentsUI/res/values-pl/strings.xml
+++ b/packages/DocumentsUI/res/values-pl/strings.xml
@@ -125,6 +125,7 @@
<string name="rename_error" msgid="4203041674883412606">"Nie udało się zmienić nazwy dokumentu"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Niektóre pliki zostały przekonwertowane"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"Zezwolić aplikacji <xliff:g id="APPNAME"><b>^1</b></xliff:g> na dostęp do katalogu <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> w pamięci masowej <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
+ <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Przyznać aplikacji <xliff:g id="APPNAME"><b>^1</b></xliff:g> dostęp do katalogu <xliff:g id="DIRECTORY"><i>^2</i></xliff:g>?"</string>
<string name="open_external_dialog_root_request" msgid="8899108702926347720">"Zezwolić aplikacji <xliff:g id="APPNAME"><b>^1</b></xliff:g> na dostęp do Twoich danych, w tym zdjęć i filmów, zapisanych w pamięci <xliff:g id="STORAGE"><i>^2</i></xliff:g>?"</string>
<string name="never_ask_again" msgid="4295278542972859268">"Nie pytaj ponownie"</string>
<string name="allow" msgid="7225948811296386551">"Zezwól"</string>
@@ -137,7 +138,22 @@
</plurals>
<string name="delete_filename_confirmation_message" msgid="5312817725577537488">"Usunąć „<xliff:g id="NAME">%1$s</xliff:g>”?"</string>
<string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"Usunąć folder „<xliff:g id="NAME">%1$s</xliff:g>” i jego zawartość?"</string>
- <!-- no translation found for delete_files_confirmation_message (8417505791395471802) -->
- <!-- no translation found for delete_folders_confirmation_message (9185648028213507769) -->
- <!-- no translation found for delete_items_confirmation_message (5376214433530243459) -->
+ <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+ <item quantity="few">Usunąć <xliff:g id="COUNT_1">%1$d</xliff:g> pliki?</item>
+ <item quantity="many">Usunąć <xliff:g id="COUNT_1">%1$d</xliff:g> plików?</item>
+ <item quantity="other">Usunąć <xliff:g id="COUNT_1">%1$d</xliff:g> pliku?</item>
+ <item quantity="one">Usunąć <xliff:g id="COUNT_0">%1$d</xliff:g> plik?</item>
+ </plurals>
+ <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+ <item quantity="few">Usunąć <xliff:g id="COUNT_1">%1$d</xliff:g> foldery wraz z zawartością?</item>
+ <item quantity="many">Usunąć <xliff:g id="COUNT_1">%1$d</xliff:g> folderów wraz z zawartością?</item>
+ <item quantity="other">Usunąć <xliff:g id="COUNT_1">%1$d</xliff:g> folderu wraz z zawartością?</item>
+ <item quantity="one">Usunąć <xliff:g id="COUNT_0">%1$d</xliff:g> folder wraz z zawartością?</item>
+ </plurals>
+ <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+ <item quantity="few">Usunąć <xliff:g id="COUNT_1">%1$d</xliff:g> elementy?</item>
+ <item quantity="many">Usunąć <xliff:g id="COUNT_1">%1$d</xliff:g> elementów?</item>
+ <item quantity="other">Usunąć <xliff:g id="COUNT_1">%1$d</xliff:g> elementu?</item>
+ <item quantity="one">Usunąć <xliff:g id="COUNT_0">%1$d</xliff:g> element?</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-pt-rBR/strings.xml b/packages/DocumentsUI/res/values-pt-rBR/strings.xml
index d34b7b6..21359c7 100644
--- a/packages/DocumentsUI/res/values-pt-rBR/strings.xml
+++ b/packages/DocumentsUI/res/values-pt-rBR/strings.xml
@@ -111,6 +111,7 @@
<string name="rename_error" msgid="4203041674883412606">"Falha ao renomear documento"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Alguns arquivos foram convertidos"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"Conceder ao <xliff:g id="APPNAME"><b>^1</b></xliff:g> acesso ao diretório <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> no <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
+ <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Conceder acesso a <xliff:g id="APPNAME"><b>^1</b></xliff:g> ao diretório <xliff:g id="DIRECTORY"><i>^2</i></xliff:g>?"</string>
<string name="open_external_dialog_root_request" msgid="8899108702926347720">"Conceder a <xliff:g id="APPNAME"><b>^1</b></xliff:g> acesso aos seus dados, incluindo fotos e vídeos, no/na <xliff:g id="STORAGE"><i>^2</i></xliff:g>?"</string>
<string name="never_ask_again" msgid="4295278542972859268">"Não perguntar novamente"</string>
<string name="allow" msgid="7225948811296386551">"Permitir"</string>
@@ -121,7 +122,16 @@
</plurals>
<string name="delete_filename_confirmation_message" msgid="5312817725577537488">"Excluir \" <xliff:g id="NAME">%1$s</xliff:g>\"?"</string>
<string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"Excluir pasta \"<xliff:g id="NAME">%1$s</xliff:g>\" e o respectivo conteúdo?"</string>
- <!-- no translation found for delete_files_confirmation_message (8417505791395471802) -->
- <!-- no translation found for delete_folders_confirmation_message (9185648028213507769) -->
- <!-- no translation found for delete_items_confirmation_message (5376214433530243459) -->
+ <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+ <item quantity="one">Excluir <xliff:g id="COUNT_1">%1$d</xliff:g> arquivos?</item>
+ <item quantity="other">Excluir <xliff:g id="COUNT_1">%1$d</xliff:g> arquivos?</item>
+ </plurals>
+ <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+ <item quantity="one">Excluir <xliff:g id="COUNT_1">%1$d</xliff:g> pastas e o respectivo conteúdo?</item>
+ <item quantity="other">Excluir <xliff:g id="COUNT_1">%1$d</xliff:g> pastas e o respectivo conteúdo?</item>
+ </plurals>
+ <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+ <item quantity="one">Excluir <xliff:g id="COUNT_1">%1$d</xliff:g> itens?</item>
+ <item quantity="other">Excluir <xliff:g id="COUNT_1">%1$d</xliff:g> itens?</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-pt-rPT/strings.xml b/packages/DocumentsUI/res/values-pt-rPT/strings.xml
index 7c82410..aea1249 100644
--- a/packages/DocumentsUI/res/values-pt-rPT/strings.xml
+++ b/packages/DocumentsUI/res/values-pt-rPT/strings.xml
@@ -111,6 +111,7 @@
<string name="rename_error" msgid="4203041674883412606">"Falha ao mudar o nome do documento"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Alguns ficheiros foram convertidos"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"Pretende conceder a <xliff:g id="APPNAME"><b>^1</b></xliff:g> acesso ao diretório <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> no(a) <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
+ <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Pretende conceder a <xliff:g id="APPNAME"><b>^1</b></xliff:g> acesso ao diretório <xliff:g id="DIRECTORY"><i>^2</i></xliff:g>?"</string>
<string name="open_external_dialog_root_request" msgid="8899108702926347720">"Pretende conceder a <xliff:g id="APPNAME"><b>^1</b></xliff:g> acesso aos seus dados, incluindo fotos e vídeos, no(a) <xliff:g id="STORAGE"><i>^2</i></xliff:g>?"</string>
<string name="never_ask_again" msgid="4295278542972859268">"Não perguntar novamente"</string>
<string name="allow" msgid="7225948811296386551">"Permitir"</string>
@@ -121,7 +122,16 @@
</plurals>
<string name="delete_filename_confirmation_message" msgid="5312817725577537488">"Pretende eliminar \"<xliff:g id="NAME">%1$s</xliff:g>\"?"</string>
<string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"Pretende eliminar a pasta \"<xliff:g id="NAME">%1$s</xliff:g>\" e os respetivos conteúdos?"</string>
- <!-- no translation found for delete_files_confirmation_message (8417505791395471802) -->
- <!-- no translation found for delete_folders_confirmation_message (9185648028213507769) -->
- <!-- no translation found for delete_items_confirmation_message (5376214433530243459) -->
+ <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+ <item quantity="other">Pretende eliminar <xliff:g id="COUNT_1">%1$d</xliff:g> ficheiros?</item>
+ <item quantity="one">Pretende eliminar <xliff:g id="COUNT_0">%1$d</xliff:g> ficheiro?</item>
+ </plurals>
+ <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+ <item quantity="other">Pretende eliminar <xliff:g id="COUNT_1">%1$d</xliff:g> pastas e os respetivos conteúdos?</item>
+ <item quantity="one">Pretende eliminar <xliff:g id="COUNT_0">%1$d</xliff:g> pasta e os respetivos conteúdos?</item>
+ </plurals>
+ <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+ <item quantity="other">Pretende eliminar <xliff:g id="COUNT_1">%1$d</xliff:g> itens?</item>
+ <item quantity="one">Pretende eliminar <xliff:g id="COUNT_0">%1$d</xliff:g> item?</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-pt/strings.xml b/packages/DocumentsUI/res/values-pt/strings.xml
index d34b7b6..21359c7 100644
--- a/packages/DocumentsUI/res/values-pt/strings.xml
+++ b/packages/DocumentsUI/res/values-pt/strings.xml
@@ -111,6 +111,7 @@
<string name="rename_error" msgid="4203041674883412606">"Falha ao renomear documento"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Alguns arquivos foram convertidos"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"Conceder ao <xliff:g id="APPNAME"><b>^1</b></xliff:g> acesso ao diretório <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> no <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
+ <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Conceder acesso a <xliff:g id="APPNAME"><b>^1</b></xliff:g> ao diretório <xliff:g id="DIRECTORY"><i>^2</i></xliff:g>?"</string>
<string name="open_external_dialog_root_request" msgid="8899108702926347720">"Conceder a <xliff:g id="APPNAME"><b>^1</b></xliff:g> acesso aos seus dados, incluindo fotos e vídeos, no/na <xliff:g id="STORAGE"><i>^2</i></xliff:g>?"</string>
<string name="never_ask_again" msgid="4295278542972859268">"Não perguntar novamente"</string>
<string name="allow" msgid="7225948811296386551">"Permitir"</string>
@@ -121,7 +122,16 @@
</plurals>
<string name="delete_filename_confirmation_message" msgid="5312817725577537488">"Excluir \" <xliff:g id="NAME">%1$s</xliff:g>\"?"</string>
<string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"Excluir pasta \"<xliff:g id="NAME">%1$s</xliff:g>\" e o respectivo conteúdo?"</string>
- <!-- no translation found for delete_files_confirmation_message (8417505791395471802) -->
- <!-- no translation found for delete_folders_confirmation_message (9185648028213507769) -->
- <!-- no translation found for delete_items_confirmation_message (5376214433530243459) -->
+ <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+ <item quantity="one">Excluir <xliff:g id="COUNT_1">%1$d</xliff:g> arquivos?</item>
+ <item quantity="other">Excluir <xliff:g id="COUNT_1">%1$d</xliff:g> arquivos?</item>
+ </plurals>
+ <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+ <item quantity="one">Excluir <xliff:g id="COUNT_1">%1$d</xliff:g> pastas e o respectivo conteúdo?</item>
+ <item quantity="other">Excluir <xliff:g id="COUNT_1">%1$d</xliff:g> pastas e o respectivo conteúdo?</item>
+ </plurals>
+ <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+ <item quantity="one">Excluir <xliff:g id="COUNT_1">%1$d</xliff:g> itens?</item>
+ <item quantity="other">Excluir <xliff:g id="COUNT_1">%1$d</xliff:g> itens?</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-ro/strings.xml b/packages/DocumentsUI/res/values-ro/strings.xml
index 54458f1..4b833b1 100644
--- a/packages/DocumentsUI/res/values-ro/strings.xml
+++ b/packages/DocumentsUI/res/values-ro/strings.xml
@@ -118,6 +118,7 @@
<string name="rename_error" msgid="4203041674883412606">"Documentul nu a putut fi redenumit"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Unele fișiere au fost convertite"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"Permiteți aplicației <xliff:g id="APPNAME"><b>^1</b></xliff:g> accesul la directorul <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> de pe <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
+ <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Permiteți aplicației <xliff:g id="APPNAME"><b>^1</b></xliff:g> să acceseze directorul <xliff:g id="DIRECTORY"><i>^2</i></xliff:g>?"</string>
<string name="open_external_dialog_root_request" msgid="8899108702926347720">"Permiteți aplicației <xliff:g id="APPNAME"><b>^1</b></xliff:g> să vă acceseze datele, inclusiv fotografiile și videoclipurile, de pe <xliff:g id="STORAGE"><i>^2</i></xliff:g>?"</string>
<string name="never_ask_again" msgid="4295278542972859268">"Nu mai întreba"</string>
<string name="allow" msgid="7225948811296386551">"Permiteți"</string>
@@ -129,7 +130,19 @@
</plurals>
<string name="delete_filename_confirmation_message" msgid="5312817725577537488">"Ștergeți „<xliff:g id="NAME">%1$s</xliff:g>”?"</string>
<string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"Ștergeți dosarul „<xliff:g id="NAME">%1$s</xliff:g>” și conținutul acestuia?"</string>
- <!-- no translation found for delete_files_confirmation_message (8417505791395471802) -->
- <!-- no translation found for delete_folders_confirmation_message (9185648028213507769) -->
- <!-- no translation found for delete_items_confirmation_message (5376214433530243459) -->
+ <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+ <item quantity="few">Ștergeți <xliff:g id="COUNT_1">%1$d</xliff:g> fișiere?</item>
+ <item quantity="other">Ștergeți <xliff:g id="COUNT_1">%1$d</xliff:g> de fișiere?</item>
+ <item quantity="one">Ștergeți <xliff:g id="COUNT_0">%1$d</xliff:g> fișier?</item>
+ </plurals>
+ <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+ <item quantity="few">Ștergeți <xliff:g id="COUNT_1">%1$d</xliff:g> dosare și conținutul acestora?</item>
+ <item quantity="other">Ștergeți <xliff:g id="COUNT_1">%1$d</xliff:g> de dosare și conținutul acestora?</item>
+ <item quantity="one">Ștergeți <xliff:g id="COUNT_0">%1$d</xliff:g> dosar și conținutul acestuia?</item>
+ </plurals>
+ <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+ <item quantity="few">Ștergeți <xliff:g id="COUNT_1">%1$d</xliff:g> elemente?</item>
+ <item quantity="other">Ștergeți <xliff:g id="COUNT_1">%1$d</xliff:g> de elemente?</item>
+ <item quantity="one">Ștergeți <xliff:g id="COUNT_0">%1$d</xliff:g> element?</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-ru/strings.xml b/packages/DocumentsUI/res/values-ru/strings.xml
index 2eda9ec..6ba635d 100644
--- a/packages/DocumentsUI/res/values-ru/strings.xml
+++ b/packages/DocumentsUI/res/values-ru/strings.xml
@@ -125,6 +125,7 @@
<string name="rename_error" msgid="4203041674883412606">"Не удалось переименовать документ"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Формат некоторых файлов изменен"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"Открыть приложению \"<xliff:g id="APPNAME"><b>^1</b></xliff:g>\" доступ к папке \"<xliff:g id="DIRECTORY"><i>^2</i></xliff:g>\" на устройстве \"<xliff:g id="STORAGE"><i>^3</i></xliff:g>\"?"</string>
+ <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Открыть приложению \"<xliff:g id="APPNAME"><b>^1</b></xliff:g>\" доступ к папке \"<xliff:g id="DIRECTORY"><i>^2</i></xliff:g>\"?"</string>
<string name="open_external_dialog_root_request" msgid="8899108702926347720">"Открыть приложению \"<xliff:g id="APPNAME"><b>^1</b></xliff:g>\" доступ к вашим данным, включая фото и видео, на носителе: <xliff:g id="STORAGE"><i>^2</i></xliff:g>?"</string>
<string name="never_ask_again" msgid="4295278542972859268">"Больше не спрашивать"</string>
<string name="allow" msgid="7225948811296386551">"Разрешить"</string>
@@ -137,7 +138,22 @@
</plurals>
<string name="delete_filename_confirmation_message" msgid="5312817725577537488">"Удалить файл \"<xliff:g id="NAME">%1$s</xliff:g>\"?"</string>
<string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"Удалить папку \"<xliff:g id="NAME">%1$s</xliff:g>\" со всем содержимым?"</string>
- <!-- no translation found for delete_files_confirmation_message (8417505791395471802) -->
- <!-- no translation found for delete_folders_confirmation_message (9185648028213507769) -->
- <!-- no translation found for delete_items_confirmation_message (5376214433530243459) -->
+ <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+ <item quantity="one">Удалить <xliff:g id="COUNT_1">%1$d</xliff:g> файл?</item>
+ <item quantity="few">Удалить <xliff:g id="COUNT_1">%1$d</xliff:g> файла?</item>
+ <item quantity="many">Удалить <xliff:g id="COUNT_1">%1$d</xliff:g> файлов?</item>
+ <item quantity="other">Удалить <xliff:g id="COUNT_1">%1$d</xliff:g> файла?</item>
+ </plurals>
+ <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+ <item quantity="one">Удалить <xliff:g id="COUNT_1">%1$d</xliff:g> папку со всем содержимым?</item>
+ <item quantity="few">Удалить <xliff:g id="COUNT_1">%1$d</xliff:g> папки со всем содержимым?</item>
+ <item quantity="many">Удалить <xliff:g id="COUNT_1">%1$d</xliff:g> папок со всем содержимым?</item>
+ <item quantity="other">Удалить <xliff:g id="COUNT_1">%1$d</xliff:g> папки со всем содержимым?</item>
+ </plurals>
+ <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+ <item quantity="one">Удалить <xliff:g id="COUNT_1">%1$d</xliff:g> объект?</item>
+ <item quantity="few">Удалить <xliff:g id="COUNT_1">%1$d</xliff:g> объекта?</item>
+ <item quantity="many">Удалить <xliff:g id="COUNT_1">%1$d</xliff:g> объектов?</item>
+ <item quantity="other">Удалить <xliff:g id="COUNT_1">%1$d</xliff:g> объекта?</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-si-rLK/strings.xml b/packages/DocumentsUI/res/values-si-rLK/strings.xml
index 1dc9a2b..41c9d4a 100644
--- a/packages/DocumentsUI/res/values-si-rLK/strings.xml
+++ b/packages/DocumentsUI/res/values-si-rLK/strings.xml
@@ -111,6 +111,7 @@
<string name="rename_error" msgid="4203041674883412606">"ලේඛනය යළි නම් කිරීම අසාර්ථක විය"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"සමහර ගොනු පරිවර්තනය කරන ලදී"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> හට <xliff:g id="STORAGE"><i>^3</i></xliff:g> මත <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> නාමාවලිය වෙත ප්රවේශය දෙන්නද?"</string>
+ <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> ප්රවේශය <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> නාමාවලිය වෙත ලබා දෙන්නද?"</string>
<string name="open_external_dialog_root_request" msgid="8899108702926347720">"<xliff:g id="STORAGE"><i>^2</i></xliff:g> හි, ඡායාරූප සහ වීඩියෝ ඇතුළුව, ඔබේ දත්තවලට <xliff:g id="APPNAME"><b>^1</b></xliff:g> හට ප්රවේශය ලබා දෙන්නද?"</string>
<string name="never_ask_again" msgid="4295278542972859268">"නැවත අසන්න එපා"</string>
<string name="allow" msgid="7225948811296386551">"අවසර දෙන්න"</string>
@@ -119,11 +120,18 @@
<item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g>ක් තෝරන ලදී</item>
<item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g>ක් තෝරන ලදී</item>
</plurals>
- <!-- no translation found for delete_filename_confirmation_message (5312817725577537488) -->
- <skip />
- <!-- no translation found for delete_foldername_confirmation_message (5885501832257285329) -->
- <skip />
- <!-- no translation found for delete_files_confirmation_message (8417505791395471802) -->
- <!-- no translation found for delete_folders_confirmation_message (9185648028213507769) -->
- <!-- no translation found for delete_items_confirmation_message (5376214433530243459) -->
+ <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"\"<xliff:g id="NAME">%1$s</xliff:g>\" මකන්නද?"</string>
+ <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"\"<xliff:g id="NAME">%1$s</xliff:g>\" ෆෝල්ඩරය හා එහි අන්තර්ගත මකන්නද?"</string>
+ <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+ <item quantity="one">ගොනු <xliff:g id="COUNT_1">%1$d</xliff:g> ක් මකන්නද?</item>
+ <item quantity="other">ගොනු <xliff:g id="COUNT_1">%1$d</xliff:g> ක් මකන්නද?</item>
+ </plurals>
+ <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+ <item quantity="one">ෆෝල්ඩර <xliff:g id="COUNT_1">%1$d</xliff:g> ක් හා එහි අන්තර්ගත මකන්නද?</item>
+ <item quantity="other">ෆෝල්ඩර <xliff:g id="COUNT_1">%1$d</xliff:g> ක් හා එහි අන්තර්ගත මකන්නද?</item>
+ </plurals>
+ <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+ <item quantity="one">අයිතම <xliff:g id="COUNT_1">%1$d</xliff:g> ක් මකන්නද?</item>
+ <item quantity="other">අයිතම <xliff:g id="COUNT_1">%1$d</xliff:g> ක් මකන්නද?</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-sk/strings.xml b/packages/DocumentsUI/res/values-sk/strings.xml
index da91574..1ff01b0 100644
--- a/packages/DocumentsUI/res/values-sk/strings.xml
+++ b/packages/DocumentsUI/res/values-sk/strings.xml
@@ -125,6 +125,7 @@
<string name="rename_error" msgid="4203041674883412606">"Premenovanie dokumentu zlyhalo"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Niektoré súbory boli konvertované"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"Udeliť aplikácii <xliff:g id="APPNAME"><b>^1</b></xliff:g> prístup k adresáru <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> v úložisku <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
+ <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Udeliť aplikácii <xliff:g id="APPNAME"><b>^1</b></xliff:g> prístup k adresáru <xliff:g id="DIRECTORY"><i>^2</i></xliff:g>?"</string>
<string name="open_external_dialog_root_request" msgid="8899108702926347720">"Chcete aplikácii <xliff:g id="APPNAME"><b>^1</b></xliff:g> udeliť prístup k dátam (vrátane fotiek a videí) v úložisku <xliff:g id="STORAGE"><i>^2</i></xliff:g>?"</string>
<string name="never_ask_again" msgid="4295278542972859268">"Nabudúce sa nepýtať"</string>
<string name="allow" msgid="7225948811296386551">"Povoliť"</string>
@@ -137,7 +138,22 @@
</plurals>
<string name="delete_filename_confirmation_message" msgid="5312817725577537488">"Odstrániť <xliff:g id="NAME">%1$s</xliff:g>?"</string>
<string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"Odstrániť priečinok <xliff:g id="NAME">%1$s</xliff:g> a jeho obsah?"</string>
- <!-- no translation found for delete_files_confirmation_message (8417505791395471802) -->
- <!-- no translation found for delete_folders_confirmation_message (9185648028213507769) -->
- <!-- no translation found for delete_items_confirmation_message (5376214433530243459) -->
+ <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+ <item quantity="few">Odstrániť <xliff:g id="COUNT_1">%1$d</xliff:g> súbory?</item>
+ <item quantity="many">Odstrániť <xliff:g id="COUNT_1">%1$d</xliff:g> súboru?</item>
+ <item quantity="other">Odstrániť <xliff:g id="COUNT_1">%1$d</xliff:g> súborov?</item>
+ <item quantity="one">Odstrániť <xliff:g id="COUNT_0">%1$d</xliff:g> súbor?</item>
+ </plurals>
+ <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+ <item quantity="few">Odstrániť <xliff:g id="COUNT_1">%1$d</xliff:g> priečinky a ich obsah?</item>
+ <item quantity="many">Odstrániť <xliff:g id="COUNT_1">%1$d</xliff:g> priečinka a jeho obsah?</item>
+ <item quantity="other">Odstrániť <xliff:g id="COUNT_1">%1$d</xliff:g> priečinkov a ich obsah?</item>
+ <item quantity="one">Odstrániť <xliff:g id="COUNT_0">%1$d</xliff:g> priečinok a jeho obsah?</item>
+ </plurals>
+ <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+ <item quantity="few">Odstrániť <xliff:g id="COUNT_1">%1$d</xliff:g> položky?</item>
+ <item quantity="many">Odstrániť <xliff:g id="COUNT_1">%1$d</xliff:g> položky?</item>
+ <item quantity="other">Odstrániť <xliff:g id="COUNT_1">%1$d</xliff:g> položiek?</item>
+ <item quantity="one">Odstrániť <xliff:g id="COUNT_0">%1$d</xliff:g> položku?</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-sl/strings.xml b/packages/DocumentsUI/res/values-sl/strings.xml
index 9a7b477..d8b983c 100644
--- a/packages/DocumentsUI/res/values-sl/strings.xml
+++ b/packages/DocumentsUI/res/values-sl/strings.xml
@@ -125,6 +125,7 @@
<string name="rename_error" msgid="4203041674883412606">"Dokumenta ni bilo mogoče preimenovati"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Nekatere datoteke so bile pretvorjene"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"Želite aplikaciji <xliff:g id="APPNAME"><b>^1</b></xliff:g> dovoliti dostop do imenika <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> v shrambi <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
+ <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Želite aplikaciji <xliff:g id="APPNAME"><b>^1</b></xliff:g> dovoliti dostop do imenika <xliff:g id="DIRECTORY"><i>^2</i></xliff:g>?"</string>
<string name="open_external_dialog_root_request" msgid="8899108702926347720">"Odobrite aplikaciji <xliff:g id="APPNAME"><b>^1</b></xliff:g> dostop do podatkov, vključno s fotografijami in videoposnetki, v shrambi <xliff:g id="STORAGE"><i>^2</i></xliff:g>?"</string>
<string name="never_ask_again" msgid="4295278542972859268">"Ne sprašuj več"</string>
<string name="allow" msgid="7225948811296386551">"Dovoli"</string>
@@ -137,7 +138,22 @@
</plurals>
<string name="delete_filename_confirmation_message" msgid="5312817725577537488">"Ali želite izbrisati »<xliff:g id="NAME">%1$s</xliff:g>«?"</string>
<string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"Ali želite izbrisati mapo »<xliff:g id="NAME">%1$s</xliff:g>« in njeno vsebino?"</string>
- <!-- no translation found for delete_files_confirmation_message (8417505791395471802) -->
- <!-- no translation found for delete_folders_confirmation_message (9185648028213507769) -->
- <!-- no translation found for delete_items_confirmation_message (5376214433530243459) -->
+ <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+ <item quantity="one">Ali želite izbrisati <xliff:g id="COUNT_1">%1$d</xliff:g> datoteko?</item>
+ <item quantity="two">Ali želite izbrisati <xliff:g id="COUNT_1">%1$d</xliff:g> datoteki?</item>
+ <item quantity="few">Ali želite izbrisati <xliff:g id="COUNT_1">%1$d</xliff:g> datoteke?</item>
+ <item quantity="other">Ali želite izbrisati <xliff:g id="COUNT_1">%1$d</xliff:g> datotek?</item>
+ </plurals>
+ <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+ <item quantity="one">Ali želite izbrisati <xliff:g id="COUNT_1">%1$d</xliff:g> mapo in njihovo vsebino?</item>
+ <item quantity="two">Ali želite izbrisati <xliff:g id="COUNT_1">%1$d</xliff:g> mapi in njihovo vsebino?</item>
+ <item quantity="few">Ali želite izbrisati <xliff:g id="COUNT_1">%1$d</xliff:g> mape in njihovo vsebino?</item>
+ <item quantity="other">Ali želite izbrisati <xliff:g id="COUNT_1">%1$d</xliff:g> map in njihovo vsebino?</item>
+ </plurals>
+ <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+ <item quantity="one">Ali želite izbrisati <xliff:g id="COUNT_1">%1$d</xliff:g> element?</item>
+ <item quantity="two">Ali želite izbrisati <xliff:g id="COUNT_1">%1$d</xliff:g> elementa?</item>
+ <item quantity="few">Ali želite izbrisati <xliff:g id="COUNT_1">%1$d</xliff:g> elemente?</item>
+ <item quantity="other">Ali želite izbrisati <xliff:g id="COUNT_1">%1$d</xliff:g> elementov?</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-sq-rAL/strings.xml b/packages/DocumentsUI/res/values-sq-rAL/strings.xml
index 6b41c60..933a537 100644
--- a/packages/DocumentsUI/res/values-sq-rAL/strings.xml
+++ b/packages/DocumentsUI/res/values-sq-rAL/strings.xml
@@ -111,6 +111,7 @@
<string name="rename_error" msgid="4203041674883412606">"Riemërtimi i dokumentit dështoi"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Disa skedarë u konvertuan"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"Jepi aplikacionit <xliff:g id="APPNAME"><b>^1</b></xliff:g> qasje te direktoria <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> në <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
+ <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"T\'i jepet aplikacionit <xliff:g id="APPNAME"><b>^1</b></xliff:g> qasje te direktoria <xliff:g id="DIRECTORY"><i>^2</i></xliff:g>?"</string>
<string name="open_external_dialog_root_request" msgid="8899108702926347720">"T\'i jepet aplikacionit <xliff:g id="APPNAME"><b>^1</b></xliff:g> qasje te të dhënat, duke përfshirë fotografitë dhe videot, në <xliff:g id="STORAGE"><i>^2</i></xliff:g>?"</string>
<string name="never_ask_again" msgid="4295278542972859268">"Mos pyet përsëri"</string>
<string name="allow" msgid="7225948811296386551">"Lejo"</string>
@@ -121,7 +122,16 @@
</plurals>
<string name="delete_filename_confirmation_message" msgid="5312817725577537488">"Të fshihet \"<xliff:g id="NAME">%1$s</xliff:g>\"?"</string>
<string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"Të fshihet dosja \"<xliff:g id="NAME">%1$s</xliff:g>\" dhe përmbajtja e saj?"</string>
- <!-- no translation found for delete_files_confirmation_message (8417505791395471802) -->
- <!-- no translation found for delete_folders_confirmation_message (9185648028213507769) -->
- <!-- no translation found for delete_items_confirmation_message (5376214433530243459) -->
+ <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+ <item quantity="other">Të fshihen <xliff:g id="COUNT_1">%1$d</xliff:g> skedarë?</item>
+ <item quantity="one">Të fshihet <xliff:g id="COUNT_0">%1$d</xliff:g> skedar?</item>
+ </plurals>
+ <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+ <item quantity="other">Të fshihen <xliff:g id="COUNT_1">%1$d</xliff:g> dosje dhe përmbajtjet e saj?</item>
+ <item quantity="one">Të fshihet <xliff:g id="COUNT_0">%1$d</xliff:g> dosje dhe përmbajtjet e saj?</item>
+ </plurals>
+ <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+ <item quantity="other">Të fshihen <xliff:g id="COUNT_1">%1$d</xliff:g> artikuj?</item>
+ <item quantity="one">Të fshihet <xliff:g id="COUNT_0">%1$d</xliff:g> artikull?</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-sr/strings.xml b/packages/DocumentsUI/res/values-sr/strings.xml
index b6ccf45..0505f42 100644
--- a/packages/DocumentsUI/res/values-sr/strings.xml
+++ b/packages/DocumentsUI/res/values-sr/strings.xml
@@ -118,6 +118,7 @@
<string name="rename_error" msgid="4203041674883412606">"Преименовање документа није успело"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Неке датотеке су конвертоване"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"Желите ли да апликацији <xliff:g id="APPNAME"><b>^1</b></xliff:g> одобрите приступ директоријуму <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> на меморијском простору <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
+ <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Желите да дозволите да <xliff:g id="APPNAME"><b>^1</b></xliff:g> приступа директоријуму <xliff:g id="DIRECTORY"><i>^2</i></xliff:g>?"</string>
<string name="open_external_dialog_root_request" msgid="8899108702926347720">"Желите да ли да дозволите да апликација <xliff:g id="APPNAME"><b>^1</b></xliff:g> приступа подацима, укључујући слике и видео снимке, на локацији <xliff:g id="STORAGE"><i>^2</i></xliff:g>?"</string>
<string name="never_ask_again" msgid="4295278542972859268">"Не питај поново"</string>
<string name="allow" msgid="7225948811296386551">"Дозволи"</string>
@@ -129,7 +130,19 @@
</plurals>
<string name="delete_filename_confirmation_message" msgid="5312817725577537488">"Желите ли да избришете „<xliff:g id="NAME">%1$s</xliff:g>“?"</string>
<string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"Желите ли да избришете директоријум „<xliff:g id="NAME">%1$s</xliff:g>“ и његов садржај?"</string>
- <!-- no translation found for delete_files_confirmation_message (8417505791395471802) -->
- <!-- no translation found for delete_folders_confirmation_message (9185648028213507769) -->
- <!-- no translation found for delete_items_confirmation_message (5376214433530243459) -->
+ <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+ <item quantity="one">Желите ли да избришете <xliff:g id="COUNT_1">%1$d</xliff:g> датотеку?</item>
+ <item quantity="few">Желите ли да избришете <xliff:g id="COUNT_1">%1$d</xliff:g> датотеке?</item>
+ <item quantity="other">Желите ли да избришете <xliff:g id="COUNT_1">%1$d</xliff:g> датотека?</item>
+ </plurals>
+ <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+ <item quantity="one">Желите ли да избришете <xliff:g id="COUNT_1">%1$d</xliff:g> директоријум и њихов садржај?</item>
+ <item quantity="few">Желите ли да избришете <xliff:g id="COUNT_1">%1$d</xliff:g> директоријума и њихов садржај?</item>
+ <item quantity="other">Желите ли да избришете <xliff:g id="COUNT_1">%1$d</xliff:g> директоријума и њихов садржај?</item>
+ </plurals>
+ <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+ <item quantity="one">Желите ли да избришете <xliff:g id="COUNT_1">%1$d</xliff:g> ставку?</item>
+ <item quantity="few">Желите ли да избришете <xliff:g id="COUNT_1">%1$d</xliff:g> ставке?</item>
+ <item quantity="other">Желите ли да избришете <xliff:g id="COUNT_1">%1$d</xliff:g> ставки?</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-sv/strings.xml b/packages/DocumentsUI/res/values-sv/strings.xml
index 67bbfdf..99f334b 100644
--- a/packages/DocumentsUI/res/values-sv/strings.xml
+++ b/packages/DocumentsUI/res/values-sv/strings.xml
@@ -111,6 +111,7 @@
<string name="rename_error" msgid="4203041674883412606">"Det gick inte att byta namn på dokumentet"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Vissa filer konverterades"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"Vill du ge <xliff:g id="APPNAME"><b>^1</b></xliff:g> åtkomst till katalogen <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> på <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
+ <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Vill du ge <xliff:g id="APPNAME"><b>^1</b></xliff:g> åtkomst till katalogen <xliff:g id="DIRECTORY"><i>^2</i></xliff:g>?"</string>
<string name="open_external_dialog_root_request" msgid="8899108702926347720">"Vill du ge <xliff:g id="APPNAME"><b>^1</b></xliff:g> åtkomst till din data (inklusive foton och videor) på <xliff:g id="STORAGE"><i>^2</i></xliff:g>?"</string>
<string name="never_ask_again" msgid="4295278542972859268">"Fråga inte igen"</string>
<string name="allow" msgid="7225948811296386551">"Tillåt"</string>
@@ -121,7 +122,16 @@
</plurals>
<string name="delete_filename_confirmation_message" msgid="5312817725577537488">"Vill du radera <xliff:g id="NAME">%1$s</xliff:g>?"</string>
<string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"Vill du radera mappen <xliff:g id="NAME">%1$s</xliff:g> och dess innehåll?"</string>
- <!-- no translation found for delete_files_confirmation_message (8417505791395471802) -->
- <!-- no translation found for delete_folders_confirmation_message (9185648028213507769) -->
- <!-- no translation found for delete_items_confirmation_message (5376214433530243459) -->
+ <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+ <item quantity="other">Vill du radera <xliff:g id="COUNT_1">%1$d</xliff:g> filer?</item>
+ <item quantity="one">Vill du radera <xliff:g id="COUNT_0">%1$d</xliff:g> fil?</item>
+ </plurals>
+ <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+ <item quantity="other">Vill du radera <xliff:g id="COUNT_1">%1$d</xliff:g> mappar och deras innehåll?</item>
+ <item quantity="one">Vill du radera <xliff:g id="COUNT_0">%1$d</xliff:g> mapp och dess innehåll?</item>
+ </plurals>
+ <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+ <item quantity="other">Vill du radera <xliff:g id="COUNT_1">%1$d</xliff:g> objekt?</item>
+ <item quantity="one">Vill du radera <xliff:g id="COUNT_0">%1$d</xliff:g> objekt?</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-sw/strings.xml b/packages/DocumentsUI/res/values-sw/strings.xml
index 168b63a..566e6a4 100644
--- a/packages/DocumentsUI/res/values-sw/strings.xml
+++ b/packages/DocumentsUI/res/values-sw/strings.xml
@@ -111,6 +111,7 @@
<string name="rename_error" msgid="4203041674883412606">"Imeshindwa kubadilisha jina la hati"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Baadhi ya faili zimebadilishwa muundo"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"Ungependa kuruhusu <xliff:g id="APPNAME"><b>^1</b></xliff:g> ifikie saraka ya <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> kwenye <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
+ <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Ungependa kuruhusu <xliff:g id="APPNAME"><b>^1</b></xliff:g> ifikie saraka ya <xliff:g id="DIRECTORY"><i>^2</i></xliff:g>?"</string>
<string name="open_external_dialog_root_request" msgid="8899108702926347720">"Ungependa kuruhusu <xliff:g id="APPNAME"><b>^1</b></xliff:g> ifikie data yako, ikiwa ni pamoja na picha na video kwenye <xliff:g id="STORAGE"><i>^2</i></xliff:g>?"</string>
<string name="never_ask_again" msgid="4295278542972859268">"Usiniulize tena"</string>
<string name="allow" msgid="7225948811296386551">"Ruhusu"</string>
@@ -121,7 +122,16 @@
</plurals>
<string name="delete_filename_confirmation_message" msgid="5312817725577537488">"Ungependa kufuta \"<xliff:g id="NAME">%1$s</xliff:g>\"?"</string>
<string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"Ungependa kufuta folda ya \"<xliff:g id="NAME">%1$s</xliff:g>\" na maudhui yake?"</string>
- <!-- no translation found for delete_files_confirmation_message (8417505791395471802) -->
- <!-- no translation found for delete_folders_confirmation_message (9185648028213507769) -->
- <!-- no translation found for delete_items_confirmation_message (5376214433530243459) -->
+ <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+ <item quantity="other">Ungependa kufuta faili <xliff:g id="COUNT_1">%1$d</xliff:g>?</item>
+ <item quantity="one">Ungependa kufuta faili <xliff:g id="COUNT_0">%1$d</xliff:g>?</item>
+ </plurals>
+ <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+ <item quantity="other">Ungependa kufuta folda <xliff:g id="COUNT_1">%1$d</xliff:g> na maudhui yaliyomo?</item>
+ <item quantity="one">Ungependa kufuta folda <xliff:g id="COUNT_0">%1$d</xliff:g> na maudhui yaliyomo?</item>
+ </plurals>
+ <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+ <item quantity="other">Ungependa kufuta vipengee <xliff:g id="COUNT_1">%1$d</xliff:g>?</item>
+ <item quantity="one">Ungependa kufuta kipengee <xliff:g id="COUNT_0">%1$d</xliff:g>?</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-sw720dp/colors.xml b/packages/DocumentsUI/res/values-sw720dp/colors.xml
new file mode 100644
index 0000000..3ecafe2
--- /dev/null
+++ b/packages/DocumentsUI/res/values-sw720dp/colors.xml
@@ -0,0 +1,19 @@
+<?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.
+-->
+
+<resources>
+ <color name="menu_search_background">#ff676f74</color>
+</resources>
diff --git a/packages/DocumentsUI/res/values-sw720dp/config.xml b/packages/DocumentsUI/res/values-sw720dp/config.xml
new file mode 100644
index 0000000..4898e74
--- /dev/null
+++ b/packages/DocumentsUI/res/values-sw720dp/config.xml
@@ -0,0 +1,20 @@
+<?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.
+-->
+
+<resources>
+ <!-- Indicates if search view is taking the whole toolbar space -->
+ <bool name="full_bar_search_view">false</bool>
+</resources>
diff --git a/packages/DocumentsUI/res/values-ta-rIN/strings.xml b/packages/DocumentsUI/res/values-ta-rIN/strings.xml
index 43543c6..9a8b4ec 100644
--- a/packages/DocumentsUI/res/values-ta-rIN/strings.xml
+++ b/packages/DocumentsUI/res/values-ta-rIN/strings.xml
@@ -111,6 +111,7 @@
<string name="rename_error" msgid="4203041674883412606">"ஆவணத்திற்கு மறுபெயரிடுவதில் தோல்வி"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"சில கோப்புகள் மாற்றப்பட்டன"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"<xliff:g id="STORAGE"><i>^3</i></xliff:g> இல் உள்ள <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> கோப்பகத்தை அணுக <xliff:g id="APPNAME"><b>^1</b></xliff:g>ஐ அனுமதிக்கவா?"</string>
+ <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"<xliff:g id="DIRECTORY"><i>^2</i></xliff:g> கோப்பகத்தை அணுக, <xliff:g id="APPNAME"><b>^1</b></xliff:g>ஐ அனுமதிக்கவா?"</string>
<string name="open_external_dialog_root_request" msgid="8899108702926347720">"<xliff:g id="STORAGE"><i>^2</i></xliff:g> இல் உள்ள படங்கள், வீடியோக்கள் உட்பட எல்லா தரவையும் அணுக, <xliff:g id="APPNAME"><b>^1</b></xliff:g>ஐ அனுமதிக்கவா?"</string>
<string name="never_ask_again" msgid="4295278542972859268">"மீண்டும் கேட்காதே"</string>
<string name="allow" msgid="7225948811296386551">"அனுமதி"</string>
@@ -121,7 +122,16 @@
</plurals>
<string name="delete_filename_confirmation_message" msgid="5312817725577537488">"\"<xliff:g id="NAME">%1$s</xliff:g>\"ஐ நீக்கவா?"</string>
<string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"\"<xliff:g id="NAME">%1$s</xliff:g>\" கோப்புறையையும் அதன் உள்ளடக்கத்தையும் நீக்கவா?"</string>
- <!-- no translation found for delete_files_confirmation_message (8417505791395471802) -->
- <!-- no translation found for delete_folders_confirmation_message (9185648028213507769) -->
- <!-- no translation found for delete_items_confirmation_message (5376214433530243459) -->
+ <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> கோப்புகளை நீக்கவா?</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> கோப்பை நீக்கவா?</item>
+ </plurals>
+ <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> கோப்புறைகளையும் அவற்றின் உள்ளடக்கத்தையும் நீக்கவா?</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> கோப்புறையையும் அதன் உள்ளடக்கத்தையும் நீக்கவா?</item>
+ </plurals>
+ <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> உருப்படிகளை நீக்கவா?</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> உருப்படியை நீக்கவா?</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-te-rIN/strings.xml b/packages/DocumentsUI/res/values-te-rIN/strings.xml
index 47d2c48..224d0db 100644
--- a/packages/DocumentsUI/res/values-te-rIN/strings.xml
+++ b/packages/DocumentsUI/res/values-te-rIN/strings.xml
@@ -111,6 +111,7 @@
<string name="rename_error" msgid="4203041674883412606">"పత్రం పేరు మార్చడంలో విఫలమైంది"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"కొన్ని పైల్లు మార్చబడ్డాయి"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"<xliff:g id="APPNAME"><b>^1</b></xliff:g>కి <xliff:g id="STORAGE"><i>^3</i></xliff:g>లో <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> డైరెక్టరీ ప్రాప్యతను మంజూరు చేయాలా?"</string>
+ <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"<xliff:g id="APPNAME"><b>^1</b></xliff:g>కి <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> డైరెక్టరీ ప్రాప్యతను మంజూరు చేయాలా?"</string>
<string name="open_external_dialog_root_request" msgid="8899108702926347720">"<xliff:g id="STORAGE"><i>^2</i></xliff:g>లో ఫోటోలు మరియు వీడియోలతో సహా మీ డేటా ప్రాప్యతను <xliff:g id="APPNAME"><b>^1</b></xliff:g>కి మంజూరు చేయాలా?"</string>
<string name="never_ask_again" msgid="4295278542972859268">"మళ్లీ అడగవద్దు"</string>
<string name="allow" msgid="7225948811296386551">"అనుమతించండి"</string>
@@ -121,7 +122,16 @@
</plurals>
<string name="delete_filename_confirmation_message" msgid="5312817725577537488">"\"<xliff:g id="NAME">%1$s</xliff:g>\"ని తొలగించాలా?"</string>
<string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"\"<xliff:g id="NAME">%1$s</xliff:g>\" ఫోల్డర్ని మరియు అందులోని కంటెంట్లను తొలగించాలా?"</string>
- <!-- no translation found for delete_files_confirmation_message (8417505791395471802) -->
- <!-- no translation found for delete_folders_confirmation_message (9185648028213507769) -->
- <!-- no translation found for delete_items_confirmation_message (5376214433530243459) -->
+ <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ఫైల్లను తొలగించాలా?</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> ఫైల్ను తొలగించాలా?</item>
+ </plurals>
+ <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ఫోల్డర్లు మరియు వీటిలోని కంటెంట్లను తొలగించాలా?</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> ఫోల్డర్ మరియు దీనిలోని కంటెంట్లను తొలగించాలా?</item>
+ </plurals>
+ <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> అంశాలను తొలగించాలా?</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> అంశాన్ని తొలగించాలా?</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-th/strings.xml b/packages/DocumentsUI/res/values-th/strings.xml
index 99009b4..af07584 100644
--- a/packages/DocumentsUI/res/values-th/strings.xml
+++ b/packages/DocumentsUI/res/values-th/strings.xml
@@ -111,6 +111,7 @@
<string name="rename_error" msgid="4203041674883412606">"ไม่สามารถเปลี่ยนชื่อเอกสาร"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"แปลงบางไฟล์แล้ว"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"ให้สิทธิ์ <xliff:g id="APPNAME"><b>^1</b></xliff:g> ในการเข้าถึงไดเรกทอรี <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> ใน <xliff:g id="STORAGE"><i>^3</i></xliff:g> ไหม"</string>
+ <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"ให้สิทธิ์ <xliff:g id="APPNAME"><b>^1</b></xliff:g> เข้าถึงไดเรกทอรี <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> ไหม"</string>
<string name="open_external_dialog_root_request" msgid="8899108702926347720">"ให้สิทธิ์ <xliff:g id="APPNAME"><b>^1</b></xliff:g> เข้าถึงข้อมูลของคุณ รวมถึงรูปภาพและวิดีโอใน <xliff:g id="STORAGE"><i>^2</i></xliff:g> ไหม"</string>
<string name="never_ask_again" msgid="4295278542972859268">"ไม่ต้องถามอีก"</string>
<string name="allow" msgid="7225948811296386551">"อนุญาต"</string>
@@ -119,11 +120,18 @@
<item quantity="other">เลือกไว้ <xliff:g id="COUNT_1">%1$d</xliff:g> รายการ</item>
<item quantity="one">เลือกไว้ <xliff:g id="COUNT_0">%1$d</xliff:g> รายการ</item>
</plurals>
- <!-- no translation found for delete_filename_confirmation_message (5312817725577537488) -->
- <skip />
- <!-- no translation found for delete_foldername_confirmation_message (5885501832257285329) -->
- <skip />
- <!-- no translation found for delete_files_confirmation_message (8417505791395471802) -->
- <!-- no translation found for delete_folders_confirmation_message (9185648028213507769) -->
- <!-- no translation found for delete_items_confirmation_message (5376214433530243459) -->
+ <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"ลบ \"<xliff:g id="NAME">%1$s</xliff:g>\" ไหม"</string>
+ <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"ลบโฟลเดอร์ \"<xliff:g id="NAME">%1$s</xliff:g>\" และเนื้อหาข้างในไหม"</string>
+ <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+ <item quantity="other">ลบ <xliff:g id="COUNT_1">%1$d</xliff:g> ไฟล์ใช่ไหม</item>
+ <item quantity="one">ลบ <xliff:g id="COUNT_0">%1$d</xliff:g> ไฟล์ใช่ไหม</item>
+ </plurals>
+ <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+ <item quantity="other">ลบ <xliff:g id="COUNT_1">%1$d</xliff:g> โฟลเดอร์และเนื้อหาข้างในใช่ไหม</item>
+ <item quantity="one">ลบ <xliff:g id="COUNT_0">%1$d</xliff:g> โฟลเดอร์และเนื้อหาข้างในใช่ไหม</item>
+ </plurals>
+ <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+ <item quantity="other">ลบ <xliff:g id="COUNT_1">%1$d</xliff:g> รายการใช่ไหม</item>
+ <item quantity="one">ลบ <xliff:g id="COUNT_0">%1$d</xliff:g> รายการใช่ไหม</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-tl/strings.xml b/packages/DocumentsUI/res/values-tl/strings.xml
index dd08e13..b2acf05 100644
--- a/packages/DocumentsUI/res/values-tl/strings.xml
+++ b/packages/DocumentsUI/res/values-tl/strings.xml
@@ -111,6 +111,7 @@
<string name="rename_error" msgid="4203041674883412606">"Hindi napalitan ang pangalan ng dokumento"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Na-convert ang ilang file"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"Bigyan ang <xliff:g id="APPNAME"><b>^1</b></xliff:g> ng access sa directory ng <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> sa <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
+ <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Bibigyan ang <xliff:g id="APPNAME"><b>^1</b></xliff:g> ng access sa direktoryong <xliff:g id="DIRECTORY"><i>^2</i></xliff:g>?"</string>
<string name="open_external_dialog_root_request" msgid="8899108702926347720">"Bigyan ang <xliff:g id="APPNAME"><b>^1</b></xliff:g> ng access sa iyong data, kabilang ang mga larawan at video, sa <xliff:g id="STORAGE"><i>^2</i></xliff:g>?"</string>
<string name="never_ask_again" msgid="4295278542972859268">"Huwag nang tatanunging muli"</string>
<string name="allow" msgid="7225948811296386551">"Payagan"</string>
@@ -121,7 +122,16 @@
</plurals>
<string name="delete_filename_confirmation_message" msgid="5312817725577537488">"Gusto mo bang i-delete ang \"<xliff:g id="NAME">%1$s</xliff:g>?\""</string>
<string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"Gusto mo bang i-delete ang folder na \"<xliff:g id="NAME">%1$s</xliff:g>\" at ang mga content nito?"</string>
- <!-- no translation found for delete_files_confirmation_message (8417505791395471802) -->
- <!-- no translation found for delete_folders_confirmation_message (9185648028213507769) -->
- <!-- no translation found for delete_items_confirmation_message (5376214433530243459) -->
+ <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+ <item quantity="one">Gusto mo bang i-delete ang <xliff:g id="COUNT_1">%1$d</xliff:g> file?</item>
+ <item quantity="other">Gusto mo bang i-delete ang <xliff:g id="COUNT_1">%1$d</xliff:g> (na) file?</item>
+ </plurals>
+ <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+ <item quantity="one">Gusto mo bang i-delete ang <xliff:g id="COUNT_1">%1$d</xliff:g> folder at mga content ng mga ito?</item>
+ <item quantity="other">Gusto mo bang i-delete ang <xliff:g id="COUNT_1">%1$d</xliff:g> na folder at mga content ng mga ito?</item>
+ </plurals>
+ <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+ <item quantity="one">Gusto mo bang i-delete ang <xliff:g id="COUNT_1">%1$d</xliff:g> item?</item>
+ <item quantity="other">Gusto mo bang i-delete ang <xliff:g id="COUNT_1">%1$d</xliff:g> na item?</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-tr/strings.xml b/packages/DocumentsUI/res/values-tr/strings.xml
index 3cc53e1..c5653c9 100644
--- a/packages/DocumentsUI/res/values-tr/strings.xml
+++ b/packages/DocumentsUI/res/values-tr/strings.xml
@@ -111,6 +111,7 @@
<string name="rename_error" msgid="4203041674883412606">"Dokümanın adı değiştirilemedi"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Bazı dosyalar dönüştürüldü"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> uygulamasına <xliff:g id="STORAGE"><i>^3</i></xliff:g> depolama alanındaki <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> dizinine erişim izni verilsin mi?"</string>
+ <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"<xliff:g id="DIRECTORY"><i>^2</i></xliff:g> dizinine erişmek için <xliff:g id="APPNAME"><b>^1</b></xliff:g> uygulamasına izin verilsin mi?"</string>
<string name="open_external_dialog_root_request" msgid="8899108702926347720">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> uygulamasının, fotoğraflar ve videolar dahil olmak üzere <xliff:g id="STORAGE"><i>^2</i></xliff:g> üzerindeki verilerinize erişmesine izin verilsin mi?"</string>
<string name="never_ask_again" msgid="4295278542972859268">"Tekrar sorma"</string>
<string name="allow" msgid="7225948811296386551">"İzin Ver"</string>
@@ -121,7 +122,16 @@
</plurals>
<string name="delete_filename_confirmation_message" msgid="5312817725577537488">"\"<xliff:g id="NAME">%1$s</xliff:g>\" silinsin mi?"</string>
<string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"\"<xliff:g id="NAME">%1$s</xliff:g>\" adlı klasör ve içindekiler silinsin mi?"</string>
- <!-- no translation found for delete_files_confirmation_message (8417505791395471802) -->
- <!-- no translation found for delete_folders_confirmation_message (9185648028213507769) -->
- <!-- no translation found for delete_items_confirmation_message (5376214433530243459) -->
+ <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> dosya silinsin mi?</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> dosya silinsin mi?</item>
+ </plurals>
+ <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> klasör ve içindekiler silinsin mi?</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> klasör ve içindekiler silinsin mi?</item>
+ </plurals>
+ <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> öğe silinsin mi?</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> öğe silinsin mi?</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-uk/strings.xml b/packages/DocumentsUI/res/values-uk/strings.xml
index f9620a0..21532b6 100644
--- a/packages/DocumentsUI/res/values-uk/strings.xml
+++ b/packages/DocumentsUI/res/values-uk/strings.xml
@@ -125,6 +125,7 @@
<string name="rename_error" msgid="4203041674883412606">"Не вдалося перейменувати документ"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Деякі файли конвертовано"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"Надати додатку <xliff:g id="APPNAME"><b>^1</b></xliff:g> доступ до каталогу <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> на пристрої пам’яті <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
+ <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Надати додатку <xliff:g id="APPNAME"><b>^1</b></xliff:g> доступ до каталогу \"<xliff:g id="DIRECTORY"><i>^2</i></xliff:g>\"?"</string>
<string name="open_external_dialog_root_request" msgid="8899108702926347720">"Надати додатку <xliff:g id="APPNAME"><b>^1</b></xliff:g> доступ до ваших даних, зокрема до фотографій і відео, які містить <xliff:g id="STORAGE"><i>^2</i></xliff:g>?"</string>
<string name="never_ask_again" msgid="4295278542972859268">"Не запитувати знову"</string>
<string name="allow" msgid="7225948811296386551">"Дозвол."</string>
@@ -137,7 +138,22 @@
</plurals>
<string name="delete_filename_confirmation_message" msgid="5312817725577537488">"Видалити файл <xliff:g id="NAME">%1$s</xliff:g>?"</string>
<string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"Видалити папку \"<xliff:g id="NAME">%1$s</xliff:g>\" та її вміст?"</string>
- <!-- no translation found for delete_files_confirmation_message (8417505791395471802) -->
- <!-- no translation found for delete_folders_confirmation_message (9185648028213507769) -->
- <!-- no translation found for delete_items_confirmation_message (5376214433530243459) -->
+ <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+ <item quantity="one">Видалити <xliff:g id="COUNT_1">%1$d</xliff:g> файл?</item>
+ <item quantity="few">Видалити <xliff:g id="COUNT_1">%1$d</xliff:g> файли?</item>
+ <item quantity="many">Видалити <xliff:g id="COUNT_1">%1$d</xliff:g> файлів?</item>
+ <item quantity="other">Видалити <xliff:g id="COUNT_1">%1$d</xliff:g> файлу?</item>
+ </plurals>
+ <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+ <item quantity="one">Видалити <xliff:g id="COUNT_1">%1$d</xliff:g> папку та їх вміст?</item>
+ <item quantity="few">Видалити <xliff:g id="COUNT_1">%1$d</xliff:g> папки та їх вміст?</item>
+ <item quantity="many">Видалити <xliff:g id="COUNT_1">%1$d</xliff:g> папок та їх вміст?</item>
+ <item quantity="other">Видалити <xliff:g id="COUNT_1">%1$d</xliff:g> папки та їх вміст?</item>
+ </plurals>
+ <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+ <item quantity="one">Видалити <xliff:g id="COUNT_1">%1$d</xliff:g> елемент?</item>
+ <item quantity="few">Видалити <xliff:g id="COUNT_1">%1$d</xliff:g> елементи?</item>
+ <item quantity="many">Видалити <xliff:g id="COUNT_1">%1$d</xliff:g> елементів?</item>
+ <item quantity="other">Видалити <xliff:g id="COUNT_1">%1$d</xliff:g> елемента?</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-ur-rPK/strings.xml b/packages/DocumentsUI/res/values-ur-rPK/strings.xml
index 76d4cee..eb0cfc8 100644
--- a/packages/DocumentsUI/res/values-ur-rPK/strings.xml
+++ b/packages/DocumentsUI/res/values-ur-rPK/strings.xml
@@ -111,6 +111,7 @@
<string name="rename_error" msgid="4203041674883412606">"دستاویز کا نام تبدیل کرنے میں ناکام"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"کچھ فائلوں کو تبدیل کیا گیا تھا"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> کو <xliff:g id="STORAGE"><i>^3</i></xliff:g> پر <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> ڈائرکٹری تک رسائی عطا کریں؟"</string>
+ <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> کو <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> ڈائرکٹری تک رسائی دیں؟"</string>
<string name="open_external_dialog_root_request" msgid="8899108702926347720">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> کو اپنے ڈیٹا بشمول <xliff:g id="STORAGE"><i>^2</i></xliff:g> پر موجود تصاویر اور ویڈیوز تک رسائی عطا کریں؟"</string>
<string name="never_ask_again" msgid="4295278542972859268">"دوبارہ نہ پوچھیں"</string>
<string name="allow" msgid="7225948811296386551">"اجازت دیں"</string>
@@ -121,7 +122,16 @@
</plurals>
<string name="delete_filename_confirmation_message" msgid="5312817725577537488">"\"<xliff:g id="NAME">%1$s</xliff:g>\" حذف کریں؟"</string>
<string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"\"<xliff:g id="NAME">%1$s</xliff:g>\" فولڈر اور اس کی مشمولات حذف کریں؟"</string>
- <!-- no translation found for delete_files_confirmation_message (8417505791395471802) -->
- <!-- no translation found for delete_folders_confirmation_message (9185648028213507769) -->
- <!-- no translation found for delete_items_confirmation_message (5376214433530243459) -->
+ <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> فائلیں حذف کریں؟</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> فائل حذف کریں؟</item>
+ </plurals>
+ <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> فولڈرز اور ان کے مشمولات حذف کریں؟</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> فولڈر اور اس کے مشمولات حذف کریں؟</item>
+ </plurals>
+ <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> آئٹمز حذف کریں؟</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> آئٹم حذف کریں؟</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-uz-rUZ/strings.xml b/packages/DocumentsUI/res/values-uz-rUZ/strings.xml
index 47f1ac1..2654308 100644
--- a/packages/DocumentsUI/res/values-uz-rUZ/strings.xml
+++ b/packages/DocumentsUI/res/values-uz-rUZ/strings.xml
@@ -110,8 +110,9 @@
<string name="menu_rename" msgid="7678802479104285353">"Qayta nomlash"</string>
<string name="rename_error" msgid="4203041674883412606">"Hujjatni qayta nomlab bo‘lmadi"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Bir nechta fayllar o‘girildi"</string>
- <string name="open_external_dialog_request" msgid="5789329484285817629">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> ilovasining <xliff:g id="STORAGE"><i>^3</i></xliff:g> xotirasidagi “<xliff:g id="DIRECTORY"><i>^2</i></xliff:g>” jildiga kirishiga ruxsat berilsinmi?"</string>
- <string name="open_external_dialog_root_request" msgid="8899108702926347720">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> ilovasining <xliff:g id="STORAGE"><i>^2</i></xliff:g> xotirasidagi ma’lumotlardan, jumladan, rasmlar va videolardan foydalanishiga ruxsat berilsinmi?"</string>
+ <string name="open_external_dialog_request" msgid="5789329484285817629">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> ilovasiga <xliff:g id="STORAGE"><i>^3</i></xliff:g> xotirasidagi “<xliff:g id="DIRECTORY"><i>^2</i></xliff:g>” jildidan foydalanishiga ruxsat berilsinmi?"</string>
+ <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> ilovasiga “<xliff:g id="DIRECTORY"><i>^2</i></xliff:g>” jildidan foydalanishiga ruxsat berilsinmi?"</string>
+ <string name="open_external_dialog_root_request" msgid="8899108702926347720">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> ilovasiga <xliff:g id="STORAGE"><i>^2</i></xliff:g> xotirasidagi ma’lumotlardan, jumladan, rasmlar va videolardan foydalanishiga ruxsat berilsinmi?"</string>
<string name="never_ask_again" msgid="4295278542972859268">"Boshqa so‘ralmasin"</string>
<string name="allow" msgid="7225948811296386551">"Ruxsat berish"</string>
<string name="deny" msgid="2081879885755434506">"Rad qilish"</string>
@@ -119,11 +120,18 @@
<item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ta belgilandi</item>
<item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> ta belgilandi</item>
</plurals>
- <!-- no translation found for delete_filename_confirmation_message (5312817725577537488) -->
- <skip />
- <!-- no translation found for delete_foldername_confirmation_message (5885501832257285329) -->
- <skip />
- <!-- no translation found for delete_files_confirmation_message (8417505791395471802) -->
- <!-- no translation found for delete_folders_confirmation_message (9185648028213507769) -->
- <!-- no translation found for delete_items_confirmation_message (5376214433530243459) -->
+ <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"“<xliff:g id="NAME">%1$s</xliff:g>” fayli o‘chirib tashlansinmi?"</string>
+ <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"“<xliff:g id="NAME">%1$s</xliff:g>” jildi ichidagi kontentlari bilan o‘chirib tashlansinmi?"</string>
+ <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ta fayl o‘chirilsinmi?</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> ta fayl o‘chirib tashlansinmi?</item>
+ </plurals>
+ <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ta jild ichidagi kontentlari bilan o‘chirib tashlansinmi?</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> ta jild ichidagi kontentlari bilan o‘chirib tashlansinmi?</item>
+ </plurals>
+ <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ta element o‘chirib tashlansinmi?</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> ta element o‘chirib tashlansinmi?</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-vi/strings.xml b/packages/DocumentsUI/res/values-vi/strings.xml
index 613f271..9af7db0 100644
--- a/packages/DocumentsUI/res/values-vi/strings.xml
+++ b/packages/DocumentsUI/res/values-vi/strings.xml
@@ -111,6 +111,7 @@
<string name="rename_error" msgid="4203041674883412606">"Không đổi được tên tài liệu"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Đã chuyển đổi một số tệp"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"Cấp cho <xliff:g id="APPNAME"><b>^1</b></xliff:g> quyền truy cập vào thư mục <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> trong <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
+ <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Cấp cho <xliff:g id="APPNAME"><b>^1</b></xliff:g> quyền truy cập thư mục <xliff:g id="DIRECTORY"><i>^2</i></xliff:g>?"</string>
<string name="open_external_dialog_root_request" msgid="8899108702926347720">"Cấp cho <xliff:g id="APPNAME"><b>^1</b></xliff:g> quyền truy cập vào dữ liệu của bạn, kể cả ảnh và video trên <xliff:g id="STORAGE"><i>^2</i></xliff:g>?"</string>
<string name="never_ask_again" msgid="4295278542972859268">"Không hỏi lại"</string>
<string name="allow" msgid="7225948811296386551">"Cho phép"</string>
@@ -121,7 +122,16 @@
</plurals>
<string name="delete_filename_confirmation_message" msgid="5312817725577537488">"Xóa \"<xliff:g id="NAME">%1$s</xliff:g>\"?"</string>
<string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"Xóa thư mục \"<xliff:g id="NAME">%1$s</xliff:g>\" và nội dung của thư mục?"</string>
- <!-- no translation found for delete_files_confirmation_message (8417505791395471802) -->
- <!-- no translation found for delete_folders_confirmation_message (9185648028213507769) -->
- <!-- no translation found for delete_items_confirmation_message (5376214433530243459) -->
+ <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+ <item quantity="other">Xóa <xliff:g id="COUNT_1">%1$d</xliff:g> tệp?</item>
+ <item quantity="one">Xóa <xliff:g id="COUNT_0">%1$d</xliff:g> tệp?</item>
+ </plurals>
+ <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+ <item quantity="other">Xóa <xliff:g id="COUNT_1">%1$d</xliff:g> thư mục và nội dung trong đó?</item>
+ <item quantity="one">Xóa <xliff:g id="COUNT_0">%1$d</xliff:g> thư mục và nội dung trong đó?</item>
+ </plurals>
+ <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+ <item quantity="other">Xóa <xliff:g id="COUNT_1">%1$d</xliff:g> mục?</item>
+ <item quantity="one">Xóa <xliff:g id="COUNT_0">%1$d</xliff:g> mục?</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-zh-rCN/strings.xml b/packages/DocumentsUI/res/values-zh-rCN/strings.xml
index ea5af3d..e3db1a0 100644
--- a/packages/DocumentsUI/res/values-zh-rCN/strings.xml
+++ b/packages/DocumentsUI/res/values-zh-rCN/strings.xml
@@ -111,8 +111,8 @@
<string name="rename_error" msgid="4203041674883412606">"无法重命名文档"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"部分文件已转换成其他格式"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"要授权<xliff:g id="APPNAME"><b>^1</b></xliff:g>访问 <xliff:g id="STORAGE"><i>^3</i></xliff:g>上的“<xliff:g id="DIRECTORY"><i>^2</i></xliff:g>”目录吗?"</string>
- <!-- no translation found for open_external_dialog_root_request (8899108702926347720) -->
- <skip />
+ <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"要授权<xliff:g id="APPNAME"><b>^1</b></xliff:g>访问<xliff:g id="DIRECTORY"><i>^2</i></xliff:g>目录吗?"</string>
+ <string name="open_external_dialog_root_request" msgid="8899108702926347720">"要授权<xliff:g id="APPNAME"><b>^1</b></xliff:g>访问您 <xliff:g id="STORAGE"><i>^2</i></xliff:g>上的数据(包括照片和视频)吗?"</string>
<string name="never_ask_again" msgid="4295278542972859268">"不再询问"</string>
<string name="allow" msgid="7225948811296386551">"允许"</string>
<string name="deny" msgid="2081879885755434506">"拒绝"</string>
@@ -122,7 +122,16 @@
</plurals>
<string name="delete_filename_confirmation_message" msgid="5312817725577537488">"要删除“<xliff:g id="NAME">%1$s</xliff:g>”吗?"</string>
<string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"要删除文件夹“<xliff:g id="NAME">%1$s</xliff:g>”及其中的内容吗?"</string>
- <!-- no translation found for delete_files_confirmation_message (8417505791395471802) -->
- <!-- no translation found for delete_folders_confirmation_message (9185648028213507769) -->
- <!-- no translation found for delete_items_confirmation_message (5376214433530243459) -->
+ <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+ <item quantity="other">删除 <xliff:g id="COUNT_1">%1$d</xliff:g> 个文件?</item>
+ <item quantity="one">删除 <xliff:g id="COUNT_0">%1$d</xliff:g> 个文件?</item>
+ </plurals>
+ <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+ <item quantity="other">删除 <xliff:g id="COUNT_1">%1$d</xliff:g> 个文件夹及其中的内容?</item>
+ <item quantity="one">删除 <xliff:g id="COUNT_0">%1$d</xliff:g> 个文件夹及其中的内容?</item>
+ </plurals>
+ <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+ <item quantity="other">删除 <xliff:g id="COUNT_1">%1$d</xliff:g> 项?</item>
+ <item quantity="one">删除 <xliff:g id="COUNT_0">%1$d</xliff:g> 项?</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-zh-rHK/strings.xml b/packages/DocumentsUI/res/values-zh-rHK/strings.xml
index 7587086..f13a4bd1 100644
--- a/packages/DocumentsUI/res/values-zh-rHK/strings.xml
+++ b/packages/DocumentsUI/res/values-zh-rHK/strings.xml
@@ -111,6 +111,7 @@
<string name="rename_error" msgid="4203041674883412606">"無法重新命名文件"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"部分檔案已轉換成其他格式"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"要為「<xliff:g id="APPNAME"><b>^1</b></xliff:g>」開放 <xliff:g id="STORAGE"><i>^3</i></xliff:g>上的「<xliff:g id="DIRECTORY"><i>^2</i></xliff:g>」目錄存取權嗎?"</string>
+ <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"要為「<xliff:g id="APPNAME"><b>^1</b></xliff:g>」開放「<xliff:g id="DIRECTORY"><i>^2</i></xliff:g>」目錄的存取權嗎?"</string>
<string name="open_external_dialog_root_request" msgid="8899108702926347720">"要向「<xliff:g id="APPNAME"><b>^1</b></xliff:g>」開放 <xliff:g id="STORAGE"><i>^2</i></xliff:g>上的相片和影片等資料的存取權嗎?"</string>
<string name="never_ask_again" msgid="4295278542972859268">"不要再詢問"</string>
<string name="allow" msgid="7225948811296386551">"允許"</string>
@@ -121,7 +122,16 @@
</plurals>
<string name="delete_filename_confirmation_message" msgid="5312817725577537488">"要刪除「<xliff:g id="NAME">%1$s</xliff:g>」嗎?"</string>
<string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"要刪除「<xliff:g id="NAME">%1$s</xliff:g>」資料夾及其內容嗎?"</string>
- <!-- no translation found for delete_files_confirmation_message (8417505791395471802) -->
- <!-- no translation found for delete_folders_confirmation_message (9185648028213507769) -->
- <!-- no translation found for delete_items_confirmation_message (5376214433530243459) -->
+ <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+ <item quantity="other">要刪除 <xliff:g id="COUNT_1">%1$d</xliff:g> 個檔案嗎?</item>
+ <item quantity="one">要刪除 <xliff:g id="COUNT_0">%1$d</xliff:g> 個檔案嗎?</item>
+ </plurals>
+ <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+ <item quantity="other">要刪除 <xliff:g id="COUNT_1">%1$d</xliff:g> 個資料夾及其內容嗎?</item>
+ <item quantity="one">要刪除 <xliff:g id="COUNT_0">%1$d</xliff:g> 個資料夾及其內容嗎?</item>
+ </plurals>
+ <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+ <item quantity="other">要刪除 <xliff:g id="COUNT_1">%1$d</xliff:g> 個項目嗎?</item>
+ <item quantity="one">要刪除 <xliff:g id="COUNT_0">%1$d</xliff:g> 個項目嗎?</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-zh-rTW/strings.xml b/packages/DocumentsUI/res/values-zh-rTW/strings.xml
index 7f13098..f8f8282 100644
--- a/packages/DocumentsUI/res/values-zh-rTW/strings.xml
+++ b/packages/DocumentsUI/res/values-zh-rTW/strings.xml
@@ -111,6 +111,7 @@
<string name="rename_error" msgid="4203041674883412606">"無法重新命名文件"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"部分檔案已轉換成其他格式"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"要允許<xliff:g id="APPNAME"><b>^1</b></xliff:g>存取 <xliff:g id="STORAGE"><i>^3</i></xliff:g>上的「<xliff:g id="DIRECTORY"><i>^2</i></xliff:g>」目錄嗎?"</string>
+ <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"要允許<xliff:g id="APPNAME"><b>^1</b></xliff:g>存取「<xliff:g id="DIRECTORY"><i>^2</i></xliff:g>」目錄嗎?"</string>
<string name="open_external_dialog_root_request" msgid="8899108702926347720">"要允許「<xliff:g id="APPNAME"><b>^1</b></xliff:g>」存取 <xliff:g id="STORAGE"><i>^2</i></xliff:g>上的資料 (包括相片和影片) 嗎?"</string>
<string name="never_ask_again" msgid="4295278542972859268">"不要再詢問"</string>
<string name="allow" msgid="7225948811296386551">"允許"</string>
@@ -121,7 +122,16 @@
</plurals>
<string name="delete_filename_confirmation_message" msgid="5312817725577537488">"要刪除「<xliff:g id="NAME">%1$s</xliff:g>」嗎?"</string>
<string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"要刪除「<xliff:g id="NAME">%1$s</xliff:g>」資料夾和當中的內容嗎?"</string>
- <!-- no translation found for delete_files_confirmation_message (8417505791395471802) -->
- <!-- no translation found for delete_folders_confirmation_message (9185648028213507769) -->
- <!-- no translation found for delete_items_confirmation_message (5376214433530243459) -->
+ <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+ <item quantity="other">要刪除 <xliff:g id="COUNT_1">%1$d</xliff:g> 個檔案嗎?</item>
+ <item quantity="one">要刪除 <xliff:g id="COUNT_0">%1$d</xliff:g> 個檔案嗎?</item>
+ </plurals>
+ <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+ <item quantity="other">要刪除 <xliff:g id="COUNT_1">%1$d</xliff:g> 個資料夾和當中的內容嗎?</item>
+ <item quantity="one">要刪除 <xliff:g id="COUNT_0">%1$d</xliff:g> 個資料夾和當中的內容嗎?</item>
+ </plurals>
+ <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+ <item quantity="other">要刪除 <xliff:g id="COUNT_1">%1$d</xliff:g> 個項目嗎?</item>
+ <item quantity="one">要刪除 <xliff:g id="COUNT_0">%1$d</xliff:g> 個項目嗎?</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-zu/strings.xml b/packages/DocumentsUI/res/values-zu/strings.xml
index 6453059..a0b9f7f 100644
--- a/packages/DocumentsUI/res/values-zu/strings.xml
+++ b/packages/DocumentsUI/res/values-zu/strings.xml
@@ -111,6 +111,7 @@
<string name="rename_error" msgid="4203041674883412606">"Yehlulekile ukuqamba kabusha idokhumenti"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Amanye amafayela aguqulelwe"</string>
<string name="open_external_dialog_request" msgid="5789329484285817629">"Nika i-<xliff:g id="APPNAME"><b>^1</b></xliff:g> ukufinyelela ekuqondiseni kwe-<xliff:g id="DIRECTORY"><i>^2</i></xliff:g> ku-<xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
+ <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"Nika ukufinyelela kwe-<xliff:g id="APPNAME"><b>^1</b></xliff:g> kwinkomba ye-<xliff:g id="DIRECTORY"><i>^2</i></xliff:g>?"</string>
<string name="open_external_dialog_root_request" msgid="8899108702926347720">"Nikeza i-<xliff:g id="APPNAME"><b>^1</b></xliff:g> ukufinyelela kudatha yakho, okufaka izithombe namavidiyo, ku-<xliff:g id="STORAGE"><i>^2</i></xliff:g>?"</string>
<string name="never_ask_again" msgid="4295278542972859268">"Ungaphindi ubuze"</string>
<string name="allow" msgid="7225948811296386551">"Vumela"</string>
@@ -121,7 +122,16 @@
</plurals>
<string name="delete_filename_confirmation_message" msgid="5312817725577537488">"Susa i-\"<xliff:g id="NAME">%1$s</xliff:g>\"?"</string>
<string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"Susa ifolda engu-\"<xliff:g id="NAME">%1$s</xliff:g>\" nokuqukethwe kwalo?"</string>
- <!-- no translation found for delete_files_confirmation_message (8417505791395471802) -->
- <!-- no translation found for delete_folders_confirmation_message (9185648028213507769) -->
- <!-- no translation found for delete_items_confirmation_message (5376214433530243459) -->
+ <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+ <item quantity="one">Susa amafayela angu-<xliff:g id="COUNT_1">%1$d</xliff:g>?</item>
+ <item quantity="other">Susa amafayela angu-<xliff:g id="COUNT_1">%1$d</xliff:g>?</item>
+ </plurals>
+ <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+ <item quantity="one">Susa amafolda angu-<xliff:g id="COUNT_1">%1$d</xliff:g> nokuqukethwe kwawo?</item>
+ <item quantity="other">Susa amafolda angu-<xliff:g id="COUNT_1">%1$d</xliff:g> nokuqukethwe kwawo?</item>
+ </plurals>
+ <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+ <item quantity="one">Susa izinto ezingu-<xliff:g id="COUNT_1">%1$d</xliff:g>?</item>
+ <item quantity="other">Susa izinto ezingu-<xliff:g id="COUNT_1">%1$d</xliff:g>?</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values/colors.xml b/packages/DocumentsUI/res/values/colors.xml
index 51e04b6..1660e26 100644
--- a/packages/DocumentsUI/res/values/colors.xml
+++ b/packages/DocumentsUI/res/values/colors.xml
@@ -24,7 +24,7 @@
<color name="window_background">#fff1f1f1</color>
<color name="drawer_background">#fff1f1f1</color>
<color name="directory_background">#fff7f7f7</color>
- <color name="menu_search_background">#ff676f74</color>
+ <color name="menu_search_background">@android:color/transparent</color>
<color name="primary_dark">@*android:color/primary_dark_material_dark</color>
<color name="primary">@*android:color/material_blue_grey_900</color>
diff --git a/packages/DocumentsUI/res/values/config.xml b/packages/DocumentsUI/res/values/config.xml
index 408603e..6590bbe 100644
--- a/packages/DocumentsUI/res/values/config.xml
+++ b/packages/DocumentsUI/res/values/config.xml
@@ -24,6 +24,9 @@
<!-- Indicates if the home directory should be hidden in the roots list, that is presented
in the drawer/left side panel ) -->
<bool name="home_root_hidden">true</bool>
- <!-- Indicates if the advanced roots like internal storage should be hidden in the roots list) -->
- <bool name="advanced_roots_hidden">true</bool>
+ <!-- Indicates if the advanced roots like internal storage should be shown in the roots list.
+ When enabled there is no menu option to toggle internal storage visibility. -->
+ <bool name="advanced_roots_shown">false</bool>
+ <!-- Indicates if search view is taking the whole toolbar space -->
+ <bool name="full_bar_search_view">true</bool>
</resources>
diff --git a/packages/DocumentsUI/res/values/strings.xml b/packages/DocumentsUI/res/values/strings.xml
index b26ee97..fb557ca 100644
--- a/packages/DocumentsUI/res/values/strings.xml
+++ b/packages/DocumentsUI/res/values/strings.xml
@@ -204,6 +204,9 @@
<string name="open_external_dialog_request">Grant <xliff:g id="appName" example="System Settings"><b>^1</b></xliff:g>
access to <xliff:g id="directory" example="Pictures"><i>^2</i></xliff:g> directory on
<xliff:g id="storage" example="SD Card"><i>^3</i></xliff:g>?</string>
+ <!-- Text in an alert dialog asking user to grant app access to a given directory in the internal storage -->
+ <string name="open_external_dialog_request_primary_volume">Grant <xliff:g id="appName" example="System Settings"><b>^1</b></xliff:g>
+ access to <xliff:g id="directory" example="Pictures"><i>^2</i></xliff:g> directory?</string>
<!-- Text in an alert dialog asking user to grant app access to all data in an external storage volume -->
<string name="open_external_dialog_root_request">Grant <xliff:g id="appName" example="System Settings"><b>^1</b></xliff:g>
access to your data, including photos and videos, on <xliff:g id="storage" example="SD Card"><i>^2</i></xliff:g>?</string>
diff --git a/packages/DocumentsUI/res/values/styles.xml b/packages/DocumentsUI/res/values/styles.xml
index b16554c..b0996aa 100644
--- a/packages/DocumentsUI/res/values/styles.xml
+++ b/packages/DocumentsUI/res/values/styles.xml
@@ -36,8 +36,6 @@
<item name="android:windowActionBar">false</item>
<item name="android:windowActionModeOverlay">true</item>
<item name="android:windowNoTitle">true</item>
- <item name="android:windowTranslucentStatus">true</item>
- <item name="android:fitsSystemWindows">false</item>
<item name="android:windowSoftInputMode">stateUnspecified|adjustUnspecified</item>
</style>
diff --git a/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java b/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java
index 54202d4..d6c742a 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java
@@ -18,6 +18,11 @@
import static com.android.documentsui.Shared.DEBUG;
import static com.android.documentsui.Shared.EXTRA_BENCHMARK;
+import static com.android.documentsui.State.ACTION_CREATE;
+import static com.android.documentsui.State.ACTION_OPEN;
+import static com.android.documentsui.State.ACTION_OPEN_TREE;
+import static com.android.documentsui.State.ACTION_GET_CONTENT;
+import static com.android.documentsui.State.ACTION_PICK_COPY_DESTINATION;
import static com.android.documentsui.State.MODE_GRID;
import android.app.Activity;
@@ -44,6 +49,7 @@
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuItem;
+import android.view.WindowManager;
import android.widget.Spinner;
import com.android.documentsui.SearchViewManager.SearchManagerListener;
@@ -98,6 +104,16 @@
@CallSuper
@Override
public void onCreate(Bundle icicle) {
+ // This flag is being set here as a result of the bug. When the flag was set in the
+ // styles.xml keyboard was messing the layout of dialogs (create dir, rename).
+ // Attempts were made to keep the flag in the main theme and to override it in the dialog
+ // layout xml or to create separate style for dialog and assign it in styles.xml.
+ // None of this brought successful results.
+ // Setting the flag works here most probably because of the timing when it is set. Also the
+ // setting might not affect the dialogs that are created in new windows or it affects them
+ // in the different way that having this in the style.
+ getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
+
// Record the time when onCreate is invoked for metric.
mStartTime = new Date().getTime();
@@ -146,7 +162,8 @@
getMenuInflater().inflate(R.menu.activity, menu);
mNavigator.update();
- mSearchManager.install((DocumentsToolbar) findViewById(R.id.toolbar));
+ boolean fullBarSearch = getResources().getBoolean(R.bool.full_bar_search_view);
+ mSearchManager.install((DocumentsToolbar) findViewById(R.id.toolbar), fullBarSearch);
return showMenu;
}
@@ -164,6 +181,7 @@
final MenuItem sortSize = menu.findItem(R.id.menu_sort_size);
final MenuItem grid = menu.findItem(R.id.menu_grid);
final MenuItem list = menu.findItem(R.id.menu_list);
+ final MenuItem advanced = menu.findItem(R.id.menu_advanced);
final MenuItem fileSize = menu.findItem(R.id.menu_file_size);
// Search uses backend ranking; no sorting, recents doesn't support sort.
@@ -175,6 +193,9 @@
grid.setVisible(mState.derivedMode != State.MODE_GRID);
list.setVisible(mState.derivedMode != State.MODE_LIST);
+ advanced.setVisible(mState.showAdvancedOption);
+ advanced.setTitle(mState.showAdvancedOption && mState.showAdvanced
+ ? R.string.menu_advanced_hide : R.string.menu_advanced_show);
fileSize.setTitle(LocalPreferences.getDisplayFileSize(this)
? R.string.menu_file_size_hide : R.string.menu_file_size_show);
@@ -194,25 +215,30 @@
return state;
}
- State state = createSharedState();
- includeState(state);
- if (DEBUG) Log.d(mTag, "Created new state object: " + state);
- return state;
- }
-
- private State createSharedState() {
State state = new State();
final Intent intent = getIntent();
state.localOnly = intent.getBooleanExtra(Intent.EXTRA_LOCAL_ONLY, false);
-
state.forceSize = intent.getBooleanExtra(DocumentsContract.EXTRA_SHOW_FILESIZE, false);
state.showSize = state.forceSize || LocalPreferences.getDisplayFileSize(this);
-
state.initAcceptMimes(intent);
state.excludedAuthorities = getExcludedAuthorities();
+ includeState(state);
+
+ // Advanced roots are shown by deafult without menu option if forced by config or intent.
+ state.showAdvanced = getResources().getBoolean(R.bool.advanced_roots_shown)
+ || intent.getBooleanExtra(DocumentsContract.EXTRA_SHOW_ADVANCED, false);
+ // Menu option is shown for whitelisted intents if advanced roots are not shown by default.
+ state.showAdvancedOption = !state.showAdvanced &&
+ (state.action == ACTION_OPEN ||
+ state.action == ACTION_CREATE ||
+ state.action == ACTION_OPEN_TREE ||
+ state.action == ACTION_GET_CONTENT);
+
+ if (DEBUG) Log.d(mTag, "Created new state object: " + state);
+
return state;
}
@@ -246,6 +272,7 @@
@Override
public boolean onOptionsItemSelected(MenuItem item) {
+ Metrics.logMenuAction(this, item.getItemId());
switch (item.getItemId()) {
case android.R.id.home:
@@ -286,6 +313,10 @@
}
return true;
+ case R.id.menu_advanced:
+ setDisplayAdvancedDevices(!mState.showAdvanced);
+ return true;
+
case R.id.menu_file_size:
setDisplayFileSize(!LocalPreferences.getDisplayFileSize(this));
return true;
@@ -378,8 +409,12 @@
public void onSearchChanged(@Nullable String query) {
// We should not get here if root is not searchable
assert(canSearchRoot());
-
reloadSearch(query);
+ }
+
+ @Override
+ public void onSearchFinished() {
+ // Restores menu icons state
invalidateOptionsMenu();
}
@@ -447,6 +482,12 @@
? DocumentsContract.buildRootUri("com.android.providers.downloads.documents",
"downloads")
: DocumentsContract.buildHomeUri();
+ }
+
+ void setDisplayAdvancedDevices(boolean display) {
+ mState.showAdvanced = display;
+ RootsFragment.get(getFragmentManager()).onDisplayStateChanged();
+ invalidateOptionsMenu();
}
void setDisplayFileSize(boolean display) {
@@ -595,10 +636,12 @@
return true;
}
} else if (keyCode == KeyEvent.KEYCODE_TAB) {
+ Metrics.logKeyboardAction(this, Metrics.ACTION_KEYBOARD_SWITCH_FOCUS);
// Tab toggles focus on the navigation drawer.
toggleNavDrawerFocus();
return true;
} else if (keyCode == KeyEvent.KEYCODE_DEL) {
+ Metrics.logKeyboardAction(this, Metrics.ACTION_KEYBOARD_BACK);
popDir();
return true;
}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/CreateDirectoryFragment.java b/packages/DocumentsUI/src/com/android/documentsui/CreateDirectoryFragment.java
index ebc9082..5b5a96e 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/CreateDirectoryFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/CreateDirectoryFragment.java
@@ -153,10 +153,12 @@
if (result != null) {
// Navigate into newly created child
mActivity.onDirectoryCreated(result);
+ Metrics.logCreateDirOperation(getContext());
} else {
- Snackbars.makeSnackbar(mActivity, R.string.create_error, Snackbar.LENGTH_SHORT).show();
+ Snackbars.makeSnackbar(mActivity, R.string.create_error, Snackbar.LENGTH_SHORT)
+ .show();
+ Metrics.logCreateDirError(getContext());
}
-
mActivity.setPending(false);
}
}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DrawerController.java b/packages/DocumentsUI/src/com/android/documentsui/DrawerController.java
index 2dbb730..7a4099a 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DrawerController.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DrawerController.java
@@ -18,6 +18,7 @@
import static com.android.documentsui.Shared.DEBUG;
+import android.annotation.IntDef;
import android.app.Activity;
import android.content.Context;
import android.support.v4.app.ActionBarDrawerToggle;
@@ -27,16 +28,44 @@
import android.view.View;
import android.widget.Toolbar;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
/**
* A facade over the various pieces comprising "roots fragment in a Drawer".
*
* @see DrawerController#create(DrawerLayout)
*/
abstract class DrawerController implements DrawerListener {
-
public static final String TAG = "DrawerController";
+ // Drawer opening triggered by tapping the navigation icon
+ public static final int OPENED_HAMBURGER = 0;
+ // Drawer opening triggered by swiping right from the edge of the screen
+ public static final int OPENED_SWIPE = 1;
+ // Mostly programmatically forced drawer opening
+ public static final int OPENED_OTHER = 2;
+
+ @IntDef(flag = true, value = {
+ OPENED_HAMBURGER,
+ OPENED_SWIPE,
+ OPENED_OTHER
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface Trigger {}
+
+ /**
+ * Toggles the drawer and sets the OPENED_OTHER as the action that causes opening the drawer.
+ * @param open
+ */
abstract void setOpen(boolean open);
+
+ /**
+ * Toggles the drawer.
+ * @param open
+ * @param trigger Indicates what action caused opening the drawer. It is ignored for closing.
+ */
+ abstract void setOpen(boolean open, @Trigger int trigger);
abstract boolean isPresent();
abstract boolean isOpen();
abstract void setTitle(String title);
@@ -92,11 +121,11 @@
* Runtime controller that manages a real drawer.
*/
private static final class RuntimeDrawerController extends DrawerController {
-
private final ActionBarDrawerToggle mToggle;
private DrawerLayout mLayout;
private View mDrawer;
private Toolbar mToolbar;
+ private @Trigger int mTrigger = OPENED_OTHER;
public RuntimeDrawerController(
DrawerLayout layout, View drawer, ActionBarDrawerToggle toggle,
@@ -113,8 +142,14 @@
@Override
void setOpen(boolean open) {
+ setOpen(open, OPENED_OTHER);
+ }
+
+ @Override
+ void setOpen(boolean open, @Trigger int trigger) {
if (open) {
mLayout.openDrawer(mDrawer);
+ mTrigger = trigger;
} else {
mLayout.closeDrawer(mDrawer);
}
@@ -148,16 +183,21 @@
@Override
public void onDrawerOpened(View drawerView) {
mToggle.onDrawerOpened(drawerView);
+ Metrics.logDrawerOpened(mToolbar.getContext(), mTrigger);
}
@Override
public void onDrawerClosed(View drawerView) {
mToggle.onDrawerClosed(drawerView);
+ mTrigger = OPENED_OTHER;
}
@Override
public void onDrawerStateChanged(int newState) {
mToggle.onDrawerStateChanged(newState);
+ if (newState == DrawerLayout.STATE_DRAGGING) {
+ mTrigger = OPENED_SWIPE;
+ }
}
}
@@ -169,6 +209,8 @@
@Override
void setOpen(boolean open) {}
+ @Override
+ void setOpen(boolean open, @Trigger int trigger) {}
@Override
boolean isOpen() {
diff --git a/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java b/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java
index bed8b29..f072011 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java
@@ -201,6 +201,8 @@
newWindow.setVisible(true);
Menus.disableHiddenItems(menu, pasteFromCb);
+ // It hides icon if searching in progress
+ mSearchManager.updateMenu();
return true;
}
@@ -210,19 +212,22 @@
case R.id.menu_create_dir:
assert(canCreateDirectory());
showCreateDirectoryDialog();
- return true;
+ break;
case R.id.menu_new_window:
createNewWindow();
- return true;
+ break;
case R.id.menu_paste_from_clipboard:
DirectoryFragment dir = getDirectoryFragment();
if (dir != null) {
dir.pasteFromClipboard();
}
- return true;
+ break;
+ default:
+ return super.onOptionsItemSelected(item);
}
- return super.onOptionsItemSelected(item);
+ Metrics.logMenuAction(this, item.getItemId());
+ return true;
}
private void createNewWindow() {
@@ -233,7 +238,7 @@
// With new multi-window mode we have to pick how we are launched.
// By default we'd be launched in-place above the existing app.
// By setting launch-to-side ActivityManager will open us to side.
- if (inMultiWindow()) {
+ if (isInMultiWindowMode()) {
intent.addFlags(Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT);
}
@@ -344,18 +349,21 @@
case KeyEvent.KEYCODE_A:
dir = getDirectoryFragment();
if (dir != null) {
+ Metrics.logKeyboardAction(this, Metrics.ACTION_KEYBOARD_SELECT_ALL);
dir.selectAllFiles();
}
return true;
case KeyEvent.KEYCODE_C:
dir = getDirectoryFragment();
if (dir != null) {
+ Metrics.logKeyboardAction(this, Metrics.ACTION_KEYBOARD_COPY);
dir.copySelectedToClipboard();
}
return true;
case KeyEvent.KEYCODE_V:
dir = getDirectoryFragment();
if (dir != null) {
+ Metrics.logKeyboardAction(this, Metrics.ACTION_KEYBOARD_PASTE);
dir.pasteFromClipboard();
}
return true;
diff --git a/packages/DocumentsUI/src/com/android/documentsui/Metrics.java b/packages/DocumentsUI/src/com/android/documentsui/Metrics.java
index e6b22e6..05cc7e6 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/Metrics.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/Metrics.java
@@ -29,7 +29,9 @@
import android.net.Uri;
import android.provider.DocumentsContract;
import android.util.Log;
+import android.view.KeyEvent;
+import com.android.documentsui.State.ActionType;
import com.android.documentsui.model.DocumentInfo;
import com.android.documentsui.model.RootInfo;
import com.android.documentsui.services.FileOperationService;
@@ -65,6 +67,11 @@
private static final String COUNT_FILEOP_EXTERNAL = "docsui_fileop_external";
private static final String COUNT_FILEOP_CANCELED = "docsui_fileop_canceled";
private static final String COUNT_STARTUP_MS = "docsui_startup_ms";
+ private static final String COUNT_DRAWER_OPENED = "docsui_drawer_opened";
+ private static final String COUNT_DRAG_N_DROP = "docsui_drag_n_drop";
+ private static final String COUNT_SEARCH = "docsui_search";
+ private static final String COUNT_MENU_ACTION = "docsui_menu_action";
+ private static final String COUNT_KEYBOARD_ACTION = "docsui_keyboard_action";
// Indices for bucketing roots in the roots histogram. "Other" is the catch-all index for any
// root that is not explicitly recognized by the Metrics code (see {@link
@@ -145,10 +152,14 @@
private static final int FILEOP_MOVE_SYSTEM_PROVIDER = 6; // Move to a system provider.
private static final int FILEOP_MOVE_EXTERNAL_PROVIDER = 7; // Move to a 3rd-party provider.
private static final int FILEOP_DELETE = 8;
+ private static final int FILEOP_RENAME = 9;
+ private static final int FILEOP_CREATE_DIR = 10;
private static final int FILEOP_OTHER_ERROR = 100;
private static final int FILEOP_DELETE_ERROR = 101;
private static final int FILEOP_MOVE_ERROR = 102;
private static final int FILEOP_COPY_ERROR = 103;
+ private static final int FILEOP_RENAME_ERROR = 104;
+ private static final int FILEOP_CREATE_DIR_ERROR = 105;
@IntDef(flag = true, value = {
FILEOP_OTHER,
@@ -159,10 +170,14 @@
FILEOP_MOVE_SYSTEM_PROVIDER,
FILEOP_MOVE_EXTERNAL_PROVIDER,
FILEOP_DELETE,
+ FILEOP_RENAME,
+ FILEOP_CREATE_DIR,
FILEOP_OTHER_ERROR,
FILEOP_COPY_ERROR,
FILEOP_MOVE_ERROR,
- FILEOP_DELETE_ERROR
+ FILEOP_DELETE_ERROR,
+ FILEOP_RENAME_ERROR,
+ FILEOP_CREATE_DIR_ERROR
})
@Retention(RetentionPolicy.SOURCE)
public @interface FileOp {}
@@ -186,8 +201,71 @@
@Retention(RetentionPolicy.SOURCE)
public @interface MetricsOpType {}
- // Codes representing different launch actions. These are used for bucketing stats in the
- // COUNT_LAUNCH_ACTION histogram.
+ // Codes representing different provider types. Used for sorting file operations when logging.
+ private static final int PROVIDER_INTRA = 0;
+ private static final int PROVIDER_SYSTEM = 1;
+ private static final int PROVIDER_EXTERNAL = 2;
+
+ @IntDef(flag = false, value = {
+ PROVIDER_INTRA,
+ PROVIDER_SYSTEM,
+ PROVIDER_EXTERNAL
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface Provider {}
+
+
+ // Codes representing different menu actions. These are used for bucketing stats in the
+ // COUNT_MENU_ACTION histogram.
+ // Both regular toolbar menu and action mode menu operations are included.
+ // Do not change or rearrange these values, that will break historical data. Only add to the
+ // list.
+ // Do not use negative numbers or zero; clearcut only handles positive integers.
+ private static final int ACTION_MENU_OTHER = 1;
+ private static final int ACTION_MENU_GRID = 2;
+ private static final int ACTION_MENU_LIST = 3;
+ private static final int ACTION_MENU_SORT = 4;
+ private static final int ACTION_MENU_SORT_NAME = 5;
+ private static final int ACTION_MENU_SORT_DATE = 6;
+ private static final int ACTION_MENU_SORT_SIZE = 7;
+ private static final int ACTION_MENU_SEARCH = 8;
+ private static final int ACTION_MENU_SHOW_SIZE = 9;
+ private static final int ACTION_MENU_SETTINGS = 10;
+ private static final int ACTION_MENU_COPY_TO = 11;
+ private static final int ACTION_MENU_MOVE_TO = 12;
+ private static final int ACTION_MENU_DELETE = 13;
+ private static final int ACTION_MENU_RENAME = 14;
+ private static final int ACTION_MENU_CREATE_DIR = 15;
+ private static final int ACTION_MENU_SELECT_ALL = 16;
+ private static final int ACTION_MENU_SHARE = 17;
+ private static final int ACTION_MENU_OPEN = 18;
+ private static final int ACTION_MENU_ADVANCED = 19;
+
+ @IntDef(flag = false, value = {
+ ACTION_MENU_OTHER,
+ ACTION_MENU_GRID,
+ ACTION_MENU_LIST,
+ ACTION_MENU_SORT,
+ ACTION_MENU_SORT_NAME,
+ ACTION_MENU_SORT_DATE,
+ ACTION_MENU_SORT_SIZE,
+ ACTION_MENU_SHOW_SIZE,
+ ACTION_MENU_SETTINGS,
+ ACTION_MENU_COPY_TO,
+ ACTION_MENU_MOVE_TO,
+ ACTION_MENU_DELETE,
+ ACTION_MENU_RENAME,
+ ACTION_MENU_CREATE_DIR,
+ ACTION_MENU_SELECT_ALL,
+ ACTION_MENU_SHARE,
+ ACTION_MENU_OPEN,
+ ACTION_MENU_ADVANCED
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface MenuAction {}
+
+ // Codes representing different menu actions. These are used for bucketing stats in the
+ // COUNT_MENU_ACTION histogram.
// Do not change or rearrange these values, that will break historical data. Only add to the
// list.
// Do not use negative numbers or zero; clearcut only handles positive integers.
@@ -213,18 +291,45 @@
@Retention(RetentionPolicy.SOURCE)
public @interface MetricsAction {}
- // Codes representing different provider types. Used for sorting file operations when logging.
- private static final int PROVIDER_INTRA = 0;
- private static final int PROVIDER_SYSTEM = 1;
- private static final int PROVIDER_EXTERNAL = 2;
+ // Codes representing different keyboard shortcut triggered actions. These are used for
+ // bucketing stats in the COUNT_KEYBOARD_ACTION histogram.
+ // Do not change or rearrange these values, that will break historical data. Only add to the
+ // list.
+ // Do not use negative numbers or zero; clearcut only handles positive integers.
+ public static final int ACTION_KEYBOARD_OTHER = 1;
+ public static final int ACTION_KEYBOARD_PASTE = 2;
+ public static final int ACTION_KEYBOARD_COPY = 3;
+ public static final int ACTION_KEYBOARD_DELETE = 4;
+ public static final int ACTION_KEYBOARD_SELECT_ALL = 5;
+ public static final int ACTION_KEYBOARD_BACK = 6;
+ public static final int ACTION_KEYBOARD_SWITCH_FOCUS = 7;
- @IntDef(flag = true, value = {
- PROVIDER_INTRA,
- PROVIDER_SYSTEM,
- PROVIDER_EXTERNAL
+ @IntDef(flag = false, value = {
+ ACTION_KEYBOARD_OTHER,
+ ACTION_KEYBOARD_PASTE,
+ ACTION_KEYBOARD_COPY,
+ ACTION_KEYBOARD_DELETE,
+ ACTION_KEYBOARD_SELECT_ALL,
+ ACTION_KEYBOARD_BACK,
+ ACTION_KEYBOARD_SWITCH_FOCUS
})
@Retention(RetentionPolicy.SOURCE)
- public @interface Provider {}
+ public @interface KeyboardAction {}
+
+ // Codes representing different actions to open the drawer. They are used for bucketing stats in
+ // the COUNT_DRAWER_OPENED histogram.
+ // Do not change or rearrange these values, that will break historical data. Only add to the
+ // list.
+ // Do not use negative numbers or zero; clearcut only handles positive integers.
+ private static final int DRAWER_OPENED_HAMBURGER = 1;
+ private static final int DRAWER_OPENED_SWIPE = 2;
+
+ @IntDef(flag = true, value = {
+ DRAWER_OPENED_HAMBURGER,
+ DRAWER_OPENED_SWIPE
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface DrawerTrigger {}
/**
* Logs when DocumentsUI is started, and how. Call this when DocumentsUI first starts up.
@@ -286,6 +391,20 @@
}
/**
+ * Logs a drawer opened event. Call this when the user opens drawer by swipe or by clicking the
+ * hamburger icon.
+ * @param context
+ * @param trigger type of action that opened the drawer
+ */
+ public static void logDrawerOpened(Context context, @DrawerController.Trigger int trigger) {
+ if (trigger == DrawerController.OPENED_HAMBURGER) {
+ logHistogram(context, COUNT_DRAWER_OPENED, DRAWER_OPENED_HAMBURGER);
+ } else if (trigger == DrawerController.OPENED_SWIPE) {
+ logHistogram(context, COUNT_DRAWER_OPENED, DRAWER_OPENED_SWIPE);
+ }
+ }
+
+ /**
* Logs file operation stats. Call this when a file operation has completed. The given
* DocumentInfo is only used to distinguish broad categories of actions (e.g. copying from one
* provider to another vs copying within a given provider). No PII is logged.
@@ -316,6 +435,28 @@
}
/**
+ * Logs create directory operation. It is a part of file operation stats. We do not
+ * differentiate between internal and external locations, all create directory operations are
+ * logged under COUNT_FILEOP_SYSTEM. Call this when a create directory operation has completed.
+ *
+ * @param context
+ */
+ public static void logCreateDirOperation(Context context) {
+ logHistogram(context, COUNT_FILEOP_SYSTEM, FILEOP_CREATE_DIR);
+ }
+
+ /**
+ * Logs rename file operation. It is a part of file operation stats. We do not differentiate
+ * between internal and external locations, all rename operations are logged under
+ * COUNT_FILEOP_SYSTEM. Call this when a rename file operation has completed.
+ *
+ * @param context
+ */
+ public static void logRenameFileOperation(Context context) {
+ logHistogram(context, COUNT_FILEOP_SYSTEM, FILEOP_RENAME);
+ }
+
+ /**
* Logs some kind of file operation error. Call this when a file operation (e.g. copy, delete)
* fails.
*
@@ -348,6 +489,28 @@
}
/**
+ * Logs create directory operation error. We do not differentiate between internal and external
+ * locations, all create directory errors are logged under COUNT_FILEOP_SYSTEM. Call this when a
+ * create directory operation fails.
+ *
+ * @param context
+ */
+ public static void logCreateDirError(Context context) {
+ logHistogram(context, COUNT_FILEOP_SYSTEM, FILEOP_CREATE_DIR);
+ }
+
+ /**
+ * Logs rename file operation error. We do not differentiate between internal and external
+ * locations, all rename errors are logged under COUNT_FILEOP_SYSTEM. Call this
+ * when a rename file operation fails.
+ *
+ * @param context
+ */
+ public static void logRenameFileError(Context context) {
+ logHistogram(context, COUNT_FILEOP_SYSTEM, FILEOP_RENAME_ERROR);
+ }
+
+ /**
* Logs the cancellation of a file operation. Call this when a Job is canceled.
* @param context
* @param operationType
@@ -357,6 +520,16 @@
}
/**
+ * Logs keyboard shortcut actions. Since keyboard shortcuts have their corresponding menu items,
+ * they are identified by menu item resource id for convenience.
+ * @param context
+ * @param keyCode
+ */
+ public static void logKeyboardAction(Context context, @KeyboardAction int action) {
+ logHistogram(context, COUNT_KEYBOARD_ACTION, action);
+ }
+
+ /**
* Logs startup time in milliseconds.
* @param context
* @param startupMs Startup time in milliseconds.
@@ -365,6 +538,25 @@
logHistogram(context, COUNT_STARTUP_MS, startupMs);
}
+ /**
+ * Logs a drag and drop action. Call this when the user drops the content triggering copy.
+ * operation.
+ *
+ * @param context
+ */
+ public static void logDragNDrop(Context context) {
+ logCount(context, COUNT_DRAG_N_DROP);
+ }
+
+ /**
+ * Logs a search. Call this when the search operation is finished.
+ *
+ * @param context
+ */
+ public static void logSearch(Context context) {
+ logCount(context, COUNT_SEARCH);
+ }
+
private static void logInterProviderFileOps(
Context context,
String histogram,
@@ -485,6 +677,74 @@
}
/**
+ * Logs menu action that was selected by user.
+ * @param context
+ * @param id Resource id of the menu item.
+ */
+ public static void logMenuAction(Context context, int id) {
+ @MenuAction int menuAction = ACTION_MENU_OTHER;
+ switch (id) {
+ case R.id.menu_grid:
+ menuAction = ACTION_MENU_GRID;
+ break;
+ case R.id.menu_list:
+ menuAction = ACTION_MENU_LIST;
+ break;
+ case R.id.menu_sort:
+ menuAction = ACTION_MENU_SORT;
+ break;
+ case R.id.menu_sort_name:
+ menuAction = ACTION_MENU_SORT_NAME;
+ break;
+ case R.id.menu_sort_date:
+ menuAction = ACTION_MENU_SORT_DATE;
+ break;
+ case R.id.menu_sort_size:
+ menuAction = ACTION_MENU_SORT_SIZE;
+ break;
+ case R.id.menu_search:
+ menuAction = ACTION_MENU_SEARCH;
+ break;
+ case R.id.menu_file_size:
+ menuAction = ACTION_MENU_SHOW_SIZE;
+ break;
+ case R.id.menu_settings:
+ menuAction = ACTION_MENU_SETTINGS;
+ break;
+ case R.id.menu_copy_to:
+ menuAction = ACTION_MENU_COPY_TO;
+ break;
+ case R.id.menu_move_to:
+ menuAction = ACTION_MENU_MOVE_TO;
+ break;
+ case R.id.menu_delete:
+ menuAction = ACTION_MENU_DELETE;
+ break;
+ case R.id.menu_rename:
+ menuAction = ACTION_MENU_RENAME;
+ break;
+ case R.id.menu_create_dir:
+ menuAction = ACTION_MENU_CREATE_DIR;
+ break;
+ case R.id.menu_select_all:
+ menuAction = ACTION_MENU_SELECT_ALL;
+ break;
+ case R.id.menu_share:
+ menuAction = ACTION_MENU_SHARE;
+ break;
+ case R.id.menu_open:
+ menuAction = ACTION_MENU_OPEN;
+ break;
+ case R.id.menu_advanced:
+ menuAction = ACTION_MENU_ADVANCED;
+ break;
+ default:
+ break;
+ }
+ logHistogram(context, COUNT_MENU_ACTION, menuAction);
+ }
+
+ /**
* Internal method for making a MetricsLogger.count call. Increments the given counter by 1.
*
* @param context
@@ -502,7 +762,7 @@
* @param name The name of the histogram.
* @param bucket The bucket to increment.
*/
- private static void logHistogram(Context context, String name, int bucket) {
+ private static void logHistogram(Context context, String name, @ActionType int bucket) {
if (DEBUG) Log.d(TAG, name + ": " + bucket);
MetricsLogger.histogram(context, name, bucket);
}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/NavigationView.java b/packages/DocumentsUI/src/com/android/documentsui/NavigationView.java
index 30c1020..f6fe47b 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/NavigationView.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/NavigationView.java
@@ -91,7 +91,7 @@
private void onNavigationIconClicked() {
if (mDrawer.isPresent()) {
- mDrawer.setOpen(true);
+ mDrawer.setOpen(true, DrawerController.OPENED_HAMBURGER);
}
}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/OpenExternalDirectoryActivity.java b/packages/DocumentsUI/src/com/android/documentsui/OpenExternalDirectoryActivity.java
index 2fe2756..854be0b 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/OpenExternalDirectoryActivity.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/OpenExternalDirectoryActivity.java
@@ -86,6 +86,7 @@
private static final String EXTRA_VOLUME_LABEL = "com.android.documentsui.VOLUME_LABEL";
private static final String EXTRA_VOLUME_UUID = "com.android.documentsui.VOLUME_UUID";
private static final String EXTRA_IS_ROOT = "com.android.documentsui.IS_ROOT";
+ private static final String EXTRA_IS_PRIMARY = "com.android.documentsui.IS_PRIMARY";
// Special directory name representing the full volume
static final String DIRECTORY_ROOT = "ROOT_DIRECTORY";
@@ -157,6 +158,13 @@
Log.d(TAG, "showFragment() for volume " + storageVolume.dump() + ", directory "
+ directoryName + ", and user " + userId);
final boolean isRoot = directoryName.equals(DIRECTORY_ROOT);
+ final boolean isPrimary = storageVolume.isPrimary();
+
+ if (isRoot && isPrimary) {
+ if (DEBUG) Log.d(TAG, "root access requested on primary volume");
+ return false;
+ }
+
final File volumeRoot = storageVolume.getPathFile();
File file;
try {
@@ -235,6 +243,7 @@
args.putString(EXTRA_VOLUME_UUID, volumeUuid);
args.putString(EXTRA_APP_LABEL, appLabel);
args.putBoolean(EXTRA_IS_ROOT, isRoot);
+ args.putBoolean(EXTRA_IS_PRIMARY, isPrimary);
final FragmentManager fm = activity.getFragmentManager();
final FragmentTransaction ft = fm.beginTransaction();
@@ -352,6 +361,7 @@
private String mVolumeLabel;
private String mAppLabel;
private boolean mIsRoot;
+ private boolean mIsPrimary;
private CheckBox mDontAskAgain;
private OpenExternalDirectoryActivity mActivity;
private AlertDialog mDialog;
@@ -367,6 +377,7 @@
mVolumeLabel = args.getString(EXTRA_VOLUME_LABEL);
mAppLabel = args.getString(EXTRA_APP_LABEL);
mIsRoot = args.getBoolean(EXTRA_IS_ROOT);
+ mIsPrimary= args.getBoolean(EXTRA_IS_PRIMARY);
}
mActivity = (OpenExternalDirectoryActivity) getActivity();
}
@@ -435,7 +446,9 @@
message = TextUtils.expandTemplate(getText(
R.string.open_external_dialog_root_request), mAppLabel, mVolumeLabel);
} else {
- message = TextUtils.expandTemplate(getText(R.string.open_external_dialog_request),
+ message = TextUtils.expandTemplate(
+ getText(mIsPrimary ? R.string.open_external_dialog_request_primary_volume
+ : R.string.open_external_dialog_request),
mAppLabel, directory, mVolumeLabel);
}
final TextView messageField = (TextView) view.findViewById(R.id.message);
diff --git a/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java b/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java
index 6efe9c8..09fadc9 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java
@@ -65,8 +65,6 @@
private static final String TAG = "RootsCache";
- private static final boolean ENABLE_SYSTEM_CACHE = true;
-
private final Context mContext;
private final ContentObserver mObserver;
private OnCacheUpdateListener mCacheUpdateListener;
@@ -200,7 +198,7 @@
synchronized (mLock) {
for (String authority : mStoppedAuthorities) {
if (DEBUG) Log.d(TAG, "Loading stopped authority " + authority);
- mRoots.putAll(authority, loadRootsForAuthority(resolver, authority));
+ mRoots.putAll(authority, loadRootsForAuthority(resolver, authority, true));
}
mStoppedAuthorities.clear();
}
@@ -219,13 +217,13 @@
if (DEBUG) {
Log.d(TAG, "Loading stopped authority " + authority);
}
- mRoots.putAll(authority, loadRootsForAuthority(resolver, authority));
+ mRoots.putAll(authority, loadRootsForAuthority(resolver, authority, true));
mStoppedAuthorities.remove(authority);
}
}
private class UpdateTask extends AsyncTask<Void, Void, Void> {
- private final String mFilterPackage;
+ private final String mForceRefreshPackage;
private final Multimap<String, RootInfo> mTaskRoots = ArrayListMultimap.create();
private final HashSet<String> mTaskStoppedAuthorities = new HashSet<>();
@@ -238,18 +236,18 @@
}
/**
- * Only update roots belonging to given package name. Other roots will
+ * Force update roots belonging to given package name. Other roots will
* be copied from cached {@link #mRoots} values.
*/
- public UpdateTask(String filterPackage) {
- mFilterPackage = filterPackage;
+ public UpdateTask(String forceRefreshPackage) {
+ mForceRefreshPackage = forceRefreshPackage;
}
@Override
protected Void doInBackground(Void... params) {
final long start = SystemClock.elapsedRealtime();
- if (mFilterPackage != null) {
+ if (mForceRefreshPackage != null) {
// We must have previously cached values to fill in non-matching
// packages, so wait around for successful first load.
if (!waitForFirstLoad()) {
@@ -302,29 +300,17 @@
return;
}
- // Try using cached roots if filtering
- boolean cacheHit = false;
- if (mFilterPackage != null && !mFilterPackage.equals(info.packageName)) {
- synchronized (mLock) {
- if (mTaskRoots.putAll(info.authority, mRoots.get(info.authority))) {
- if (DEBUG) Log.d(TAG, "Used cached roots for " + info.authority);
- cacheHit = true;
- }
- }
- }
-
- // Cache miss, or loading everything
- if (!cacheHit) {
- mTaskRoots.putAll(info.authority,
- loadRootsForAuthority(mContext.getContentResolver(), info.authority));
- }
+ final boolean forceRefresh = Objects.equals(mForceRefreshPackage, info.packageName);
+ mTaskRoots.putAll(info.authority, loadRootsForAuthority(mContext.getContentResolver(),
+ info.authority, forceRefresh));
}
}
/**
* Bring up requested provider and query for all active roots.
*/
- private Collection<RootInfo> loadRootsForAuthority(ContentResolver resolver, String authority) {
+ private Collection<RootInfo> loadRootsForAuthority(ContentResolver resolver, String authority,
+ boolean forceRefresh) {
if (DEBUG) Log.d(TAG, "Loading roots for " + authority);
synchronized (mObservedAuthorities) {
@@ -336,7 +322,7 @@
}
final Uri rootsUri = DocumentsContract.buildRootsUri(authority);
- if (ENABLE_SYSTEM_CACHE) {
+ if (!forceRefresh) {
// Look for roots data that we might have cached for ourselves in the
// long-lived system process.
final Bundle systemCache = resolver.getCache(rootsUri);
@@ -363,14 +349,12 @@
ContentProviderClient.releaseQuietly(client);
}
- if (ENABLE_SYSTEM_CACHE) {
- // Cache these freshly parsed roots over in the long-lived system
- // process, in case our process goes away. The system takes care of
- // invalidating the cache if the package or Uri changes.
- final Bundle systemCache = new Bundle();
- systemCache.putParcelableArrayList(TAG, roots);
- resolver.putCache(rootsUri, systemCache);
- }
+ // Cache these freshly parsed roots over in the long-lived system
+ // process, in case our process goes away. The system takes care of
+ // invalidating the cache if the package or Uri changes.
+ final Bundle systemCache = new Bundle();
+ systemCache.putParcelableArrayList(TAG, roots);
+ resolver.putCache(rootsUri, systemCache);
return roots;
}
@@ -384,8 +368,8 @@
synchronized (mLock) {
RootInfo root = getRootLocked(authority, rootId);
if (root == null) {
- mRoots.putAll(
- authority, loadRootsForAuthority(mContext.getContentResolver(), authority));
+ mRoots.putAll(authority,
+ loadRootsForAuthority(mContext.getContentResolver(), authority, false));
root = getRootLocked(authority, rootId);
}
return root;
@@ -493,6 +477,11 @@
continue;
}
+ if (!state.showAdvanced && root.isAdvanced()) {
+ if (DEBUG) Log.d(TAG, "Excluding root because: unwanted advanced device.");
+ continue;
+ }
+
if (state.localOnly && !root.isLocalOnly()) {
if (DEBUG) Log.d(TAG, "Excluding root because: unwanted non-local device.");
continue;
diff --git a/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java b/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java
index 35da8cc..5f665c0 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java
@@ -17,6 +17,7 @@
package com.android.documentsui;
import static com.android.documentsui.Shared.DEBUG;
+import static com.android.documentsui.State.ACTION_OPEN_TREE;
import android.app.Fragment;
import android.app.FragmentManager;
@@ -117,7 +118,7 @@
Intent handlerAppIntent = getArguments().getParcelable(EXTRA_INCLUDE_APPS);
- mAdapter = new RootsAdapter(context, result, handlerAppIntent);
+ mAdapter = new RootsAdapter(context, result, handlerAppIntent, state);
mList.setAdapter(mAdapter);
onCurrentRootChanged();
@@ -308,8 +309,8 @@
* @param handlerAppIntent When not null, apps capable of handling the original
* intent will be included in list of roots (in special section at bottom).
*/
- public RootsAdapter(
- Context context, Collection<RootInfo> roots, @Nullable Intent handlerAppIntent) {
+ public RootsAdapter(Context context, Collection<RootInfo> roots,
+ @Nullable Intent handlerAppIntent, State state) {
super(context, 0);
final List<RootItem> libraries = new ArrayList<>();
@@ -320,8 +321,6 @@
if (root.isHome() && Shared.isHomeRootHidden(context)) {
continue;
- } else if (root.isAdvanced() && Shared.areAdvancedRootsHidden(context)) {
- continue;
} else if (root.isLibrary()) {
if (DEBUG) Log.d(TAG, "Adding " + root + " as library.");
libraries.add(item);
diff --git a/packages/DocumentsUI/src/com/android/documentsui/SearchViewManager.java b/packages/DocumentsUI/src/com/android/documentsui/SearchViewManager.java
index 4d0ba4b..945ed34 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/SearchViewManager.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/SearchViewManager.java
@@ -23,7 +23,9 @@
import android.provider.DocumentsContract.Root;
import android.text.TextUtils;
import android.util.Log;
+import android.view.Menu;
import android.view.MenuItem;
+import android.view.MenuItem.OnActionExpandListener;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnFocusChangeListener;
@@ -36,10 +38,12 @@
* Manages searching UI behavior.
*/
final class SearchViewManager implements
- SearchView.OnCloseListener, OnQueryTextListener, OnClickListener, OnFocusChangeListener {
+ SearchView.OnCloseListener, OnQueryTextListener, OnClickListener, OnFocusChangeListener,
+ OnActionExpandListener {
public interface SearchManagerListener {
void onSearchChanged(@Nullable String query);
+ void onSearchFinished();
}
public static final String TAG = "SearchManger";
@@ -48,10 +52,11 @@
private boolean mSearchExpanded;
private String mCurrentSearch;
private boolean mIgnoreNextClose;
+ private boolean mFullBar;
private DocumentsToolbar mActionBar;
- private MenuItem mMenu;
- private SearchView mView;
+ private MenuItem mMenuItem;
+ private SearchView mSearchView;
public SearchViewManager(SearchManagerListener listener, @Nullable Bundle savedState) {
mListener = listener;
@@ -62,45 +67,61 @@
mListener = listener;
}
- public void install(DocumentsToolbar actionBar) {
- // assert(mActionBar == null);
-
+ public void install(DocumentsToolbar actionBar, boolean isFullBarSearch) {
mActionBar = actionBar;
- mMenu = actionBar.getSearchMenu();
- mView = (SearchView) mMenu.getActionView();
+ mMenuItem = actionBar.getSearchMenu();
+ mSearchView = (SearchView) mMenuItem.getActionView();
- mView.setOnQueryTextListener(this);
- mView.setOnCloseListener(this);
- mView.setOnSearchClickListener(this);
- mView.setOnQueryTextFocusChangeListener(this);
+ mSearchView.setOnQueryTextListener(this);
+ mSearchView.setOnCloseListener(this);
+ mSearchView.setOnSearchClickListener(this);
+ mSearchView.setOnQueryTextFocusChangeListener(this);
+
+ mFullBar = isFullBarSearch;
+ if (mFullBar) {
+ mMenuItem.setShowAsActionFlags(MenuItem.SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW
+ | MenuItem.SHOW_AS_ACTION_ALWAYS);
+ mMenuItem.setOnActionExpandListener(this);
+ }
restoreSearch();
}
/**
+ * Used to hide menu icons, when the search is being restored. Needed because search restoration
+ * is done before onPrepareOptionsMenu(Menu menu) that is overriding the icons visibility.
+ */
+ public void updateMenu() {
+ if (isSearching() && mFullBar) {
+ Menu menu = mActionBar.getMenu();
+ menu.setGroupVisible(R.id.group_hide_when_searching, false);
+ }
+ }
+
+ /**
* @param root Info about the current directory.
*/
void update(RootInfo root) {
- if (mMenu == null) {
+ if (mMenuItem == null) {
if (DEBUG) Log.d(TAG, "update called before Search MenuItem installed.");
return;
}
if (mCurrentSearch != null) {
- mMenu.expandActionView();
+ mMenuItem.expandActionView();
- mView.setIconified(false);
- mView.clearFocus();
- mView.setQuery(mCurrentSearch, false);
+ mSearchView.setIconified(false);
+ mSearchView.clearFocus();
+ mSearchView.setQuery(mCurrentSearch, false);
} else {
- mView.clearFocus();
- if (!mView.isIconified()) {
+ mSearchView.clearFocus();
+ if (!mSearchView.isIconified()) {
mIgnoreNextClose = true;
- mView.setIconified(true);
+ mSearchView.setIconified(true);
}
- if (mMenu.isActionViewExpanded()) {
- mMenu.collapseActionView();
+ if (mMenuItem.isActionViewExpanded()) {
+ mMenuItem.collapseActionView();
}
}
@@ -109,7 +130,7 @@
}
void showMenu(boolean visible) {
- if (mMenu == null) {
+ if (mMenuItem == null) {
if (DEBUG) Log.d(TAG, "showMenu called before Search MenuItem installed.");
return;
}
@@ -118,7 +139,7 @@
mCurrentSearch = null;
}
- mMenu.setVisible(visible);
+ mMenuItem.setVisible(visible);
}
/**
@@ -129,46 +150,49 @@
boolean cancelSearch() {
if (isExpanded() || isSearching()) {
// If the query string is not empty search view won't get iconified
- mView.setQuery("", false);
- // Causes calling onClose(). onClose() is triggering directory content update.
- mView.setIconified(true);
+ mSearchView.setQuery("", false);
+
+ if (mFullBar) {
+ onClose();
+ } else {
+ // Causes calling onClose(). onClose() is triggering directory content update.
+ mSearchView.setIconified(true);
+ }
return true;
}
return false;
}
+ /**
+ * Sets search view into the searching state. Used to restore state after device orientation
+ * change.
+ */
private void restoreSearch() {
if (isSearching()) {
+ if(mFullBar) {
+ mMenuItem.expandActionView();
+ } else {
+ mSearchView.setIconified(false);
+ }
onSearchExpanded();
- mView.setIconified(false);
- mView.setQuery(mCurrentSearch, false);
- mView.clearFocus();
+ mSearchView.setQuery(mCurrentSearch, false);
+ mSearchView.clearFocus();
}
}
private void onSearchExpanded() {
mSearchExpanded = true;
- }
-
- boolean isSearching() {
- return mCurrentSearch != null;
- }
-
- boolean isExpanded() {
- return mSearchExpanded;
+ if(mFullBar) {
+ Menu menu = mActionBar.getMenu();
+ menu.setGroupVisible(R.id.group_hide_when_searching, false);
+ } else {
+ // If search in full-bar mode it will be logged in FilesActivity#onOptionsItemSelected
+ Metrics.logMenuAction(mActionBar.getContext(), R.id.menu_search);
+ }
}
/**
- * Called when owning activity is saving state to be used to restore state during creation.
- * @param state Bundle to save state too
- */
- public void onSaveInstanceState(Bundle state) {
- state.putString(Shared.EXTRA_QUERY, mCurrentSearch);
- }
-
- /**
- * Clears the search. Clears the SearchView background color. Triggers refreshing of the
- * directory content.
+ * Clears the search. Triggers refreshing of the directory content.
* @return True if the default behavior of clearing/dismissing SearchView should be overridden.
* False otherwise.
*/
@@ -187,13 +211,26 @@
mListener.onSearchChanged(mCurrentSearch);
}
}
+
+ if(mFullBar) {
+ mMenuItem.collapseActionView();
+ }
+ mListener.onSearchFinished();
+
return false;
}
/**
- * Sets mSearchExpanded. Called when search icon is clicked to start search. Used to detect when
- * the view expanded instead of onMenuItemActionExpand, because SearchView has showAsAction set
- * to always and onMenuItemAction* methods are not called.
+ * Called when owning activity is saving state to be used to restore state during creation.
+ * @param state Bundle to save state too
+ */
+ public void onSaveInstanceState(Bundle state) {
+ state.putString(Shared.EXTRA_QUERY, mCurrentSearch);
+ }
+
+ /**
+ * Sets mSearchExpanded. Called when search icon is clicked to start search for both search view
+ * modes.
*/
@Override
public void onClick(View v) {
@@ -203,19 +240,22 @@
@Override
public boolean onQueryTextSubmit(String query) {
mCurrentSearch = query;
- mView.clearFocus();
+ mSearchView.clearFocus();
if (mListener != null) {
mListener.onSearchChanged(mCurrentSearch);
}
return true;
}
+ /**
+ * Used to detect and handle back button pressed event when search is expanded.
+ */
@Override
public void onFocusChange(View v, boolean hasFocus) {
if (!hasFocus) {
if (mCurrentSearch == null) {
- mView.setIconified(true);
- } else if (TextUtils.isEmpty(mView.getQuery())) {
+ mSearchView.setIconified(true);
+ } else if (TextUtils.isEmpty(mSearchView.getQuery())) {
cancelSearch();
}
}
@@ -226,8 +266,34 @@
return false;
}
+ @Override
+ public boolean onMenuItemActionCollapse(MenuItem item) {
+ Menu menu = mActionBar.getMenu();
+ menu.setGroupVisible(R.id.group_hide_when_searching, true);
+
+ // Handles case when search view is collapsed by using the arrow on the left of the bar
+ if (isExpanded() || isSearching()) {
+ cancelSearch();
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ public boolean onMenuItemActionExpand(MenuItem item) {
+ return true;
+ }
+
String getCurrentSearch() {
return mCurrentSearch;
}
+ boolean isSearching() {
+ return mCurrentSearch != null;
+ }
+
+ boolean isExpanded() {
+ return mSearchExpanded;
+ }
+
}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/Shared.java b/packages/DocumentsUI/src/com/android/documentsui/Shared.java
index d21afee..2c60d4a 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/Shared.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/Shared.java
@@ -22,6 +22,11 @@
import android.text.format.DateUtils;
import android.text.format.Time;
import android.view.WindowManager;
+
+import com.android.documentsui.State.ActionType;
+
+import static com.android.documentsui.State.ACTION_OPEN_TREE;
+
import android.app.AlertDialog;
import java.text.Collator;
@@ -176,11 +181,4 @@
return context.getResources().getBoolean(R.bool.home_root_hidden);
}
- /*
- * Indicates if the advanced roots should be hidden.
- */
- public static boolean areAdvancedRootsHidden(Context context) {
- return context.getResources().getBoolean(R.bool.advanced_roots_hidden);
- }
-
}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/State.java b/packages/DocumentsUI/src/com/android/documentsui/State.java
index 16b7660..c7d60e3 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/State.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/State.java
@@ -43,10 +43,19 @@
private static final String TAG = "State";
+ @IntDef(flag = true, value = {
+ ACTION_BROWSE,
+ ACTION_PICK_COPY_DESTINATION,
+ ACTION_OPEN,
+ ACTION_CREATE,
+ ACTION_GET_CONTENT,
+ ACTION_OPEN_TREE
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface ActionType {}
// File manager and related private picking activity.
public static final int ACTION_BROWSE = 1;
public static final int ACTION_PICK_COPY_DESTINATION = 2;
-
// All public picking activities
public static final int ACTION_OPEN = 3;
public static final int ACTION_CREATE = 4;
@@ -69,7 +78,7 @@
public static final int SORT_ORDER_LAST_MODIFIED = 2;
public static final int SORT_ORDER_SIZE = 3;
- public int action;
+ public @ActionType int action;
public String[] acceptMimes;
/** Derived from local preferences */
@@ -84,6 +93,8 @@
public boolean forceSize;
public boolean showSize;
public boolean localOnly;
+ public boolean showAdvancedOption;
+ public boolean showAdvanced;
public boolean restored;
/*
* Indicates handler was an external app, like photos.
@@ -185,6 +196,8 @@
out.writeInt(forceSize ? 1 : 0);
out.writeInt(showSize ? 1 : 0);
out.writeInt(localOnly ? 1 : 0);
+ out.writeInt(showAdvancedOption ? 1 : 0);
+ out.writeInt(showAdvanced ? 1 : 0);
out.writeInt(restored ? 1 : 0);
out.writeInt(external ? 1 : 0);
DurableUtils.writeToParcel(out, stack);
@@ -214,6 +227,8 @@
state.forceSize = in.readInt() != 0;
state.showSize = in.readInt() != 0;
state.localOnly = in.readInt() != 0;
+ state.showAdvancedOption = in.readInt() != 0;
+ state.showAdvanced = in.readInt() != 0;
state.restored = in.readInt() != 0;
state.external = in.readInt() != 0;
DurableUtils.readFromParcel(in, state.stack);
diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java
index 4acf85e..c2bb4eb 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java
@@ -85,6 +85,7 @@
import com.android.documentsui.Events.MotionInputEvent;
import com.android.documentsui.Menus;
import com.android.documentsui.MessageBar;
+import com.android.documentsui.Metrics;
import com.android.documentsui.R;
import com.android.documentsui.RecentsLoader;
import com.android.documentsui.RootsCache;
@@ -105,6 +106,7 @@
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.Collections;
+import java.util.Iterator;
import java.util.List;
import java.util.Objects;
@@ -594,6 +596,7 @@
@Override
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
+ Metrics.logMenuAction(getContext(), item.getItemId());
Selection selection = mSelectionManager.getSelection(new Selection());
@@ -1061,8 +1064,19 @@
}
public void selectAllFiles() {
+ // Exclude disabled files
+ List<String> enabled = new ArrayList<String>();
+ for (String id : mAdapter.getModelIds()) {
+ Cursor cursor = getModel().getItem(id);
+ String docMimeType = getCursorString(cursor, Document.COLUMN_MIME_TYPE);
+ int docFlags = getCursorInt(cursor, Document.COLUMN_FLAGS);
+ if (isDocumentEnabled(docMimeType, docFlags)) {
+ enabled.add(id);
+ }
+ }
+
// Only select things currently visible in the adapter.
- boolean changed = mSelectionManager.setItemsSelected(mAdapter.getModelIds(), true);
+ boolean changed = mSelectionManager.setItemsSelected(enabled, true);
if (changed) {
updateDisplayState();
}
@@ -1084,7 +1098,7 @@
}
// Make all items draggable.
- view.setOnLongClickListener(mDragHelper);
+ view.setOnLongClickListener(onLongClickListener);
}
private View.OnDragListener mOnDragListener = new View.OnDragListener() {
@@ -1124,6 +1138,7 @@
if (Objects.equals(src, dst)) {
return false;
}
+ Metrics.logDragNDrop(getContext());
copyFromClipData(event.getClipData(), dst);
return true;
}
@@ -1336,6 +1351,7 @@
// This has to be handled here instead of in a keyboard shortcut, because
// keyboard shortcuts all have to be modified with the 'Ctrl' key.
if (mSelectionManager.hasSelection()) {
+ Metrics.logKeyboardAction(getContext(), Metrics.ACTION_KEYBOARD_DELETE);
deleteDocuments(mSelectionManager.getSelection());
}
// Always handle the key, even if there was nothing to delete. This is a
@@ -1387,9 +1403,10 @@
}
}
- private DragStartHelper mDragHelper = new DragStartHelper(null) {
+ private DragStartHelper.OnDragStartListener mOnDragStartListener =
+ new DragStartHelper.OnDragStartListener() {
@Override
- protected boolean onDragStart(View v) {
+ public boolean onDragStart(View v, DragStartHelper helper) {
if (isSelected(getModelId(v))) {
List<DocumentInfo> docs = getDraggableDocuments(v);
if (docs.isEmpty()) {
@@ -1409,6 +1426,15 @@
}
};
+ private DragStartHelper mDragHelper = new DragStartHelper(null, mOnDragStartListener);
+
+ private View.OnLongClickListener onLongClickListener = new View.OnLongClickListener() {
+ @Override
+ public boolean onLongClick(View v) {
+ return mDragHelper.onLongClick(v);
+ }
+ };
+
// Previously we listened to events with one class, only to bounce them forward
// to GestureDetector. We're still doing that here, but with a single class
// that reduces overall complexity in our glue code.
@@ -1439,7 +1465,7 @@
// Detect drag events. When a drag is detected, intercept the rest of the gesture.
View itemView = rv.findChildViewUnder(e.getX(), e.getY());
- if (itemView != null && mDragHelper.handleTouch(itemView, e)) {
+ if (itemView != null && mDragHelper.onTouch(itemView, e)) {
return true;
}
// Forward unhandled events to the GestureDetector.
@@ -1451,7 +1477,7 @@
@Override
public void onTouchEvent(RecyclerView rv, MotionEvent e) {
View itemView = rv.findChildViewUnder(e.getX(), e.getY());
- mDragHelper.handleTouch(itemView, e);
+ mDragHelper.onTouch(itemView, e);
// Note: even though this event is being handled as part of a drag gesture, continue
// forwarding to the GestureDetector. The detector needs to see the entire cluster of
// events in order to properly interpret gestures.
@@ -1612,6 +1638,9 @@
@Override
public void onLoadFinished(Loader<DirectoryResult> loader, DirectoryResult result) {
if (!isAdded()) return;
+ if (mSearchMode) {
+ Metrics.logSearch(getContext());
+ }
State state = getDisplayState();
diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/FragmentTuner.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/FragmentTuner.java
index faa8e38..016cc9e 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/dirlist/FragmentTuner.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/FragmentTuner.java
@@ -148,11 +148,15 @@
MenuItem share = menu.findItem(R.id.menu_share);
MenuItem delete = menu.findItem(R.id.menu_delete);
MenuItem rename = menu.findItem(R.id.menu_rename);
+ MenuItem selectAll = menu.findItem(R.id.menu_select_all);
open.setVisible(true);
share.setVisible(false);
delete.setVisible(false);
rename.setVisible(false);
+ selectAll.setVisible(mState.allowMultiple);
+
+ Menus.disableHiddenItems(menu);
}
@Override
diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/RenameDocumentFragment.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/RenameDocumentFragment.java
index 884abbb..73aa366 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/dirlist/RenameDocumentFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/RenameDocumentFragment.java
@@ -44,6 +44,7 @@
import com.android.documentsui.BaseActivity;
import com.android.documentsui.DocumentsApplication;
+import com.android.documentsui.Metrics;
import com.android.documentsui.R;
import com.android.documentsui.Shared;
import com.android.documentsui.Snackbars;
@@ -227,11 +228,13 @@
@Override
protected void onPostExecute(DocumentInfo result) {
- if (result == null) {
+ if (result != null) {
+ Metrics.logRenameFileOperation(getContext());
+ } else {
Snackbars.makeSnackbar(mActivity, R.string.rename_error, Snackbar.LENGTH_SHORT)
.show();
+ Metrics.logRenameFileError(getContext());
}
-
mActivity.setPending(false);
}
}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/services/CopyJob.java b/packages/DocumentsUI/src/com/android/documentsui/services/CopyJob.java
index 9ed2abf..f10af43 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/services/CopyJob.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/services/CopyJob.java
@@ -45,6 +45,8 @@
import android.os.RemoteException;
import android.provider.DocumentsContract;
import android.provider.DocumentsContract.Document;
+import android.system.ErrnoException;
+import android.system.Os;
import android.text.format.DateUtils;
import android.util.Log;
import android.webkit.MimeTypeMap;
@@ -451,7 +453,7 @@
ParcelFileDescriptor srcFile = null;
ParcelFileDescriptor dstFile = null;
InputStream in = null;
- OutputStream out = null;
+ ParcelFileDescriptor.AutoCloseOutputStream out = null;
boolean success = false;
try {
@@ -502,6 +504,8 @@
makeCopyProgress(len);
}
+ // Need to invoke IoUtils.close explicitly to avoid from ignoring errors at flush.
+ IoUtils.close(dstFile.getFileDescriptor());
srcFile.checkError();
} catch (IOException e) {
throw new ResourceException(
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/RootsCacheTest.java b/packages/DocumentsUI/tests/src/com/android/documentsui/RootsCacheTest.java
index e73dd8c..2e81545 100644
--- a/packages/DocumentsUI/tests/src/com/android/documentsui/RootsCacheTest.java
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/RootsCacheTest.java
@@ -55,6 +55,7 @@
mState = new State();
mState.action = State.ACTION_OPEN;
+ mState.showAdvanced = true;
mState.localOnly = false;
}
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/bots/DirectoryListBot.java b/packages/DocumentsUI/tests/src/com/android/documentsui/bots/DirectoryListBot.java
index da9f9c3..7c1e2196 100644
--- a/packages/DocumentsUI/tests/src/com/android/documentsui/bots/DirectoryListBot.java
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/bots/DirectoryListBot.java
@@ -167,7 +167,7 @@
return true;
}
- private UiObject findDocumentsList() {
+ public UiObject findDocumentsList() {
return findObject(
"com.android.documentsui:id/container_directory",
DIR_LIST_ID);
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/bots/UiBot.java b/packages/DocumentsUI/tests/src/com/android/documentsui/bots/UiBot.java
index 5b53caf..4c8dc00 100644
--- a/packages/DocumentsUI/tests/src/com/android/documentsui/bots/UiBot.java
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/bots/UiBot.java
@@ -162,7 +162,9 @@
}
UiObject findSearchViewIcon() {
- return findObject("com.android.documentsui:id/menu_search", "android:id/search_button");
+ return mContext.getResources().getBoolean(R.bool.full_bar_search_view)
+ ? findObject("com.android.documentsui:id/menu_search")
+ : findObject("com.android.documentsui:id/menu_search", "android:id/search_button");
}
UiObject findActionModeBar() {
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityContainer.java b/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityContainer.java
index b1d42e7..a7e4e12 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityContainer.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityContainer.java
@@ -464,7 +464,7 @@
return 0;
}
- private int getLayoutIdFor(SecurityMode securityMode) {
+ protected int getLayoutIdFor(SecurityMode securityMode) {
switch (securityMode) {
case Pattern: return R.layout.keyguard_pattern_view;
case PIN: return R.layout.keyguard_pin_view;
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityModel.java b/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityModel.java
index 454221a..2b549f1 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityModel.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityModel.java
@@ -77,6 +77,7 @@
case DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC:
case DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC:
case DevicePolicyManager.PASSWORD_QUALITY_COMPLEX:
+ case DevicePolicyManager.PASSWORD_QUALITY_MANAGED:
return SecurityMode.Password;
case DevicePolicyManager.PASSWORD_QUALITY_SOMETHING:
diff --git a/packages/MtpDocumentsProvider/jni/com_android_mtp_AppFuse.cpp b/packages/MtpDocumentsProvider/jni/com_android_mtp_AppFuse.cpp
index 1d4ed1d..eb96015 100644
--- a/packages/MtpDocumentsProvider/jni/com_android_mtp_AppFuse.cpp
+++ b/packages/MtpDocumentsProvider/jni/com_android_mtp_AppFuse.cpp
@@ -52,6 +52,8 @@
static jmethodID app_fuse_get_file_size;
static jmethodID app_fuse_read_object_bytes;
static jmethodID app_fuse_write_object_bytes;
+static jmethodID app_fuse_flush_file_handle;
+static jmethodID app_fuse_close_file_handle;
static jfieldID app_fuse_buffer;
// NOTE:
@@ -307,7 +309,8 @@
const uint32_t size = in->size;
const void* const buffer = reinterpret_cast<const uint8_t*>(in) + sizeof(fuse_write_in);
uint32_t written_size;
- const int result = write_object_bytes(it->second, offset, size, buffer, &written_size);
+ const int result = write_object_bytes(
+ in->fh, it->second, offset, size, buffer, &written_size);
if (result < 0) {
return result;
}
@@ -320,13 +323,13 @@
const fuse_release_in* in,
FuseResponse<void>* /* out */) {
handles_.erase(in->fh);
- return 0;
+ return env_->CallIntMethod(self_, app_fuse_close_file_handle, file_handle_to_jlong(in->fh));
}
int handle_fuse_flush(const fuse_in_header& /* header */,
- const void* /* in */,
+ const fuse_flush_in* in,
FuseResponse<void>* /* out */) {
- return 0;
+ return env_->CallIntMethod(self_, app_fuse_flush_file_handle, file_handle_to_jlong(in->fh));
}
template <typename T, typename S>
@@ -382,8 +385,10 @@
return read_size;
}
- int write_object_bytes(int inode, uint64_t offset, uint32_t size, const void* buffer,
- uint32_t* written_size) {
+ int write_object_bytes(uint64_t handle, int inode, uint64_t offset, uint32_t size,
+ const void* buffer, uint32_t* written_size) {
+ static_assert(sizeof(uint64_t) <= sizeof(jlong),
+ "jlong must be able to express any uint64_t values");
ScopedLocalRef<jbyteArray> array(
env_,
static_cast<jbyteArray>(env_->GetObjectField(self_, app_fuse_buffer)));
@@ -394,15 +399,28 @@
}
memcpy(bytes.get(), buffer, size);
}
- *written_size = env_->CallIntMethod(
- self_, app_fuse_write_object_bytes, inode, offset, size, array.get());
- if (env_->ExceptionCheck()) {
- env_->ExceptionClear();
- return -EIO;
+ const int result = env_->CallIntMethod(
+ self_,
+ app_fuse_write_object_bytes,
+ file_handle_to_jlong(handle),
+ inode,
+ offset,
+ size,
+ array.get());
+ if (result < 0) {
+ return result;
}
+ *written_size = result;
return 0;
}
+ static jlong file_handle_to_jlong(uint64_t handle) {
+ static_assert(
+ sizeof(uint64_t) <= sizeof(jlong),
+ "jlong must be able to express any uint64_t values");
+ return static_cast<jlong>(handle);
+ }
+
static void fuse_reply(int fd, int unique, int reply_code, void* reply_data,
size_t reply_size) {
// Don't send any data for error case.
@@ -511,15 +529,21 @@
return -1;
}
- app_fuse_buffer = env->GetFieldID(app_fuse_class, "mBuffer", "[B");
- if (app_fuse_buffer == nullptr) {
- ALOGE("Can't find mBuffer");
+ app_fuse_write_object_bytes = env->GetMethodID(app_fuse_class, "writeObjectBytes", "(JIJI[B)I");
+ if (app_fuse_write_object_bytes == nullptr) {
+ ALOGE("Can't find writeObjectBytes");
return -1;
}
- app_fuse_write_object_bytes = env->GetMethodID(app_fuse_class, "writeObjectBytes", "(IJI[B)I");
- if (app_fuse_write_object_bytes == nullptr) {
- ALOGE("Can't find getWriteObjectBytes");
+ app_fuse_flush_file_handle = env->GetMethodID(app_fuse_class, "flushFileHandle", "(J)I");
+ if (app_fuse_flush_file_handle == nullptr) {
+ ALOGE("Can't find flushFileHandle");
+ return -1;
+ }
+
+ app_fuse_close_file_handle = env->GetMethodID(app_fuse_class, "closeFileHandle", "(J)I");
+ if (app_fuse_close_file_handle == nullptr) {
+ ALOGE("Can't find closeFileHandle");
return -1;
}
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/AppFuse.java b/packages/MtpDocumentsProvider/src/com/android/mtp/AppFuse.java
index 777dc60..88858a8 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/AppFuse.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/AppFuse.java
@@ -20,6 +20,7 @@
import android.os.ParcelFileDescriptor;
import android.os.Process;
import android.os.storage.StorageManager;
+import android.system.ErrnoException;
import android.system.OsConstants;
import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
@@ -34,6 +35,8 @@
System.loadLibrary("appfuse_jni");
}
+ private static final boolean DEBUG = false;
+
/**
* Max read amount specified at the FUSE kernel implementation.
* The value is copied from sdcard.c.
@@ -94,7 +97,8 @@
public ParcelFileDescriptor openFile(int i, int mode) throws FileNotFoundException {
Preconditions.checkArgument(
mode == ParcelFileDescriptor.MODE_READ_ONLY ||
- mode == ParcelFileDescriptor.MODE_WRITE_ONLY);
+ mode == (ParcelFileDescriptor.MODE_WRITE_ONLY |
+ ParcelFileDescriptor.MODE_TRUNCATE));
return ParcelFileDescriptor.open(new File(
getMountPoint(),
Integer.toString(i)),
@@ -127,6 +131,7 @@
/**
* Handles writing bytes for the give inode.
+ * @param fileHandle
* @param inode
* @param offset Offset for file bytes.
* @param size Size for file bytes.
@@ -134,7 +139,23 @@
* @return Number of read bytes. Must not be negative.
* @throws IOException
*/
- int writeObjectBytes(int inode, long offset, int size, byte[] bytes) throws IOException;
+ int writeObjectBytes(long fileHandle, int inode, long offset, int size, byte[] bytes)
+ throws IOException, ErrnoException;
+
+ /**
+ * Flushes bytes for file handle.
+ * @param fileHandle
+ * @throws IOException
+ * @throws ErrnoException
+ */
+ void flushFileHandle(long fileHandle) throws IOException, ErrnoException;
+
+ /**
+ * Closes file handle.
+ * @param fileHandle
+ * @throws IOException
+ */
+ void closeFileHandle(long fileHandle) throws IOException, ErrnoException;
}
@UsedByNative("com_android_mtp_AppFuse.cpp")
@@ -142,10 +163,8 @@
private long getFileSize(int inode) {
try {
return mCallback.getFileSize(inode);
- } catch (FileNotFoundException e) {
- return -OsConstants.ENOENT;
- } catch (UnsupportedOperationException e) {
- return -OsConstants.ENOTSUP;
+ } catch (Exception error) {
+ return -getErrnoFromException(error);
}
}
@@ -159,20 +178,62 @@
// It's OK to share the same mBuffer among requests because the requests are processed
// by AppFuseMessageThread sequentially.
return mCallback.readObjectBytes(inode, offset, size, mBuffer);
- } catch (IOException e) {
- return -OsConstants.EIO;
- } catch (UnsupportedOperationException e) {
- return -OsConstants.ENOTSUP;
+ } catch (Exception error) {
+ return -getErrnoFromException(error);
}
}
@UsedByNative("com_android_mtp_AppFuse.cpp")
@WorkerThread
- private /* unsgined */ int writeObjectBytes(int inode,
+ private /* unsgined */ int writeObjectBytes(long fileHandler,
+ int inode,
/* unsigned */ long offset,
/* unsigned */ int size,
- byte[] bytes) throws IOException {
- return mCallback.writeObjectBytes(inode, offset, size, bytes);
+ byte[] bytes) {
+ try {
+ return mCallback.writeObjectBytes(fileHandler, inode, offset, size, bytes);
+ } catch (Exception error) {
+ return -getErrnoFromException(error);
+ }
+ }
+
+ @UsedByNative("com_android_mtp_AppFuse.cpp")
+ @WorkerThread
+ private int flushFileHandle(long fileHandle) {
+ try {
+ mCallback.flushFileHandle(fileHandle);
+ return 0;
+ } catch (Exception error) {
+ return -getErrnoFromException(error);
+ }
+ }
+
+ @UsedByNative("com_android_mtp_AppFuse.cpp")
+ @WorkerThread
+ private int closeFileHandle(long fileHandle) {
+ try {
+ mCallback.closeFileHandle(fileHandle);
+ return 0;
+ } catch (Exception error) {
+ return -getErrnoFromException(error);
+ }
+ }
+
+ private static int getErrnoFromException(Exception error) {
+ if (DEBUG) {
+ Log.e(MtpDocumentsProvider.TAG, "AppFuse callbacks", error);
+ }
+ if (error instanceof FileNotFoundException) {
+ return OsConstants.ENOENT;
+ } else if (error instanceof IOException) {
+ return OsConstants.EIO;
+ } else if (error instanceof UnsupportedOperationException) {
+ return OsConstants.ENOTSUP;
+ } else if (error instanceof IllegalArgumentException) {
+ return OsConstants.EINVAL;
+ } else {
+ return OsConstants.EIO;
+ }
}
private native boolean native_start_app_fuse_loop(int fd);
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java
index 9f64046ce..50781bf 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java
@@ -17,6 +17,7 @@
package com.android.mtp;
import android.content.ContentResolver;
+import android.content.Context;
import android.content.UriPermission;
import android.content.res.AssetFileDescriptor;
import android.content.res.Resources;
@@ -38,11 +39,16 @@
import android.provider.DocumentsContract;
import android.provider.DocumentsProvider;
import android.provider.Settings;
+import android.system.ErrnoException;
+import android.system.Os;
+import android.system.OsConstants;
import android.util.Log;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
+import java.io.File;
+import java.io.FileDescriptor;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.HashMap;
@@ -82,6 +88,7 @@
private MtpDatabase mDatabase;
private AppFuse mAppFuse;
private ServiceIntentSender mIntentSender;
+ private Context mContext;
/**
* Provides singleton instance to MtpDocumentsService.
@@ -93,6 +100,7 @@
@Override
public boolean onCreate() {
sSingleton = this;
+ mContext = getContext();
mResources = getContext().getResources();
mMtpManager = new MtpManager(getContext());
mResolver = getContext().getContentResolver();
@@ -137,12 +145,14 @@
@VisibleForTesting
boolean onCreateForTesting(
+ Context context,
Resources resources,
MtpManager mtpManager,
ContentResolver resolver,
MtpDatabase database,
StorageManager storageManager,
ServiceIntentSender intentSender) {
+ mContext = context;
mResources = resources;
mMtpManager = mtpManager;
mResolver = resolver;
@@ -232,43 +242,43 @@
try {
openDevice(identifier.mDeviceId);
final MtpDeviceRecord device = getDeviceToolkit(identifier.mDeviceId).mDeviceRecord;
- switch (mode) {
- case "r":
- long fileSize;
- try {
- fileSize = getFileSize(documentId);
- } catch (UnsupportedOperationException exception) {
- fileSize = -1;
- }
- // MTP getPartialObject operation does not support files that are larger than
- // 4GB. Fallback to non-seekable file descriptor.
- if (MtpDeviceRecord.isPartialReadSupported(
- device.operationsSupported, fileSize)) {
- return mAppFuse.openFile(
- Integer.parseInt(documentId), ParcelFileDescriptor.MODE_READ_ONLY);
- } else {
- return getPipeManager(identifier).readDocument(mMtpManager, identifier);
- }
- case "w":
- // TODO: Clear the parent document loader task (if exists) and call notify
- // when writing is completed.
- if (MtpDeviceRecord.isWritingSupported(device.operationsSupported)) {
- return getPipeManager(identifier).writeDocument(
- getContext(), mMtpManager, identifier, device.operationsSupported);
- } else {
- throw new UnsupportedOperationException(
- "The device does not support writing operation.");
- }
- case "rw":
- // TODO: Add support for "rw" mode.
+ // Turn off MODE_CREATE because openDocument does not allow to create new files.
+ final int modeFlag =
+ ParcelFileDescriptor.parseMode(mode) & ~ParcelFileDescriptor.MODE_CREATE;
+ if ((modeFlag & ParcelFileDescriptor.MODE_READ_ONLY) != 0) {
+ long fileSize;
+ try {
+ fileSize = getFileSize(documentId);
+ } catch (UnsupportedOperationException exception) {
+ fileSize = -1;
+ }
+ if (MtpDeviceRecord.isPartialReadSupported(
+ device.operationsSupported, fileSize)) {
+ return mAppFuse.openFile(Integer.parseInt(documentId), modeFlag);
+ } else {
+ // If getPartialObject{|64} are not supported for the device, returns
+ // non-seekable pipe FD instead.
+ return getPipeManager(identifier).readDocument(mMtpManager, identifier);
+ }
+ } else if ((modeFlag & ParcelFileDescriptor.MODE_WRITE_ONLY) != 0) {
+ // TODO: Clear the parent document loader task (if exists) and call notify
+ // when writing is completed.
+ if (MtpDeviceRecord.isWritingSupported(device.operationsSupported)) {
+ return mAppFuse.openFile(Integer.parseInt(documentId), modeFlag);
+ } else {
throw new UnsupportedOperationException(
- "The provider does not support 'rw' mode.");
- default:
- throw new IllegalArgumentException("Unknown mode for openDocument: " + mode);
+ "The device does not support writing operation.");
+ }
+ } else {
+ // TODO: Add support for "rw" mode.
+ throw new UnsupportedOperationException("The provider does not support 'rw' mode.");
}
+ } catch (FileNotFoundException | RuntimeException error) {
+ Log.e(MtpDocumentsProvider.TAG, "openDocument", error);
+ throw error;
} catch (IOException error) {
Log.e(MtpDocumentsProvider.TAG, "openDocument", error);
- throw new FileNotFoundException(error.getMessage());
+ throw new IllegalStateException(error);
}
}
@@ -595,6 +605,13 @@
}
private class AppFuseCallback implements AppFuse.Callback {
+ private final Map<Long, MtpFileWriter> mWriters = new HashMap<>();
+
+ @Override
+ public long getFileSize(int inode) throws FileNotFoundException {
+ return MtpDocumentsProvider.this.getFileSize(String.valueOf(inode));
+ }
+
@Override
public long readObjectBytes(
int inode, long offset, long size, byte[] buffer) throws IOException {
@@ -617,15 +634,43 @@
}
@Override
- public long getFileSize(int inode) throws FileNotFoundException {
- return MtpDocumentsProvider.this.getFileSize(String.valueOf(inode));
+ public int writeObjectBytes(
+ long fileHandle, int inode, long offset, int size, byte[] bytes)
+ throws IOException, ErrnoException {
+ final MtpFileWriter writer;
+ if (mWriters.containsKey(fileHandle)) {
+ writer = mWriters.get(fileHandle);
+ } else {
+ writer = new MtpFileWriter(mContext, String.valueOf(inode));
+ mWriters.put(fileHandle, writer);
+ }
+ return writer.write(offset, size, bytes);
}
@Override
- public int writeObjectBytes(int inode, long offset, int size, byte[] bytes)
- throws IOException {
- // TODO: Implement it.
- throw new IOException();
+ public void flushFileHandle(long fileHandle) throws IOException, ErrnoException {
+ final MtpFileWriter writer = mWriters.get(fileHandle);
+ if (writer == null) {
+ // File handle for reading.
+ return;
+ }
+ final MtpDeviceRecord device = getDeviceToolkit(
+ mDatabase.createIdentifier(writer.getDocumentId()).mDeviceId).mDeviceRecord;
+ writer.flush(mMtpManager, mDatabase, device.operationsSupported);
+ }
+
+ @Override
+ public void closeFileHandle(long fileHandle) throws IOException, ErrnoException {
+ final MtpFileWriter writer = mWriters.get(fileHandle);
+ if (writer == null) {
+ // File handle for reading.
+ return;
+ }
+ try {
+ writer.close();
+ } finally {
+ mWriters.remove(fileHandle);
+ }
}
}
}
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpFileWriter.java b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpFileWriter.java
new file mode 100644
index 0000000..3e1bedc
--- /dev/null
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpFileWriter.java
@@ -0,0 +1,108 @@
+/*
+ * 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.mtp;
+
+import android.content.Context;
+import android.mtp.MtpObjectInfo;
+import android.os.ParcelFileDescriptor;
+import android.system.ErrnoException;
+import android.system.Os;
+import android.system.OsConstants;
+
+import com.android.internal.util.Preconditions;
+
+import java.io.File;
+import java.io.IOException;
+
+class MtpFileWriter implements AutoCloseable {
+ final ParcelFileDescriptor mCacheFd;
+ final String mDocumentId;
+ boolean mDirty;
+
+ MtpFileWriter(Context context, String documentId) throws IOException {
+ mDocumentId = documentId;
+ mDirty = false;
+ final File tempFile = File.createTempFile("mtp", "tmp", context.getCacheDir());
+ mCacheFd = ParcelFileDescriptor.open(
+ tempFile,
+ ParcelFileDescriptor.MODE_READ_WRITE |
+ ParcelFileDescriptor.MODE_TRUNCATE |
+ ParcelFileDescriptor.MODE_CREATE);
+ tempFile.delete();
+ }
+
+ String getDocumentId() {
+ return mDocumentId;
+ }
+
+ int write(long offset, int size, byte[] bytes) throws IOException, ErrnoException {
+ Preconditions.checkArgumentNonnegative(offset, "offset");
+ Preconditions.checkArgumentNonnegative(size, "size");
+ Preconditions.checkArgument(size <= bytes.length);
+ if (size == 0) {
+ return 0;
+ }
+ mDirty = true;
+ Os.lseek(mCacheFd.getFileDescriptor(), offset, OsConstants.SEEK_SET);
+ return Os.write(mCacheFd.getFileDescriptor(), bytes, 0, size);
+ }
+
+ void flush(MtpManager manager, MtpDatabase database, int[] operationsSupported)
+ throws IOException, ErrnoException {
+ // Skip unnecessary flush.
+ if (!mDirty) {
+ return;
+ }
+
+ // Get the placeholder object info.
+ final Identifier identifier = database.createIdentifier(mDocumentId);
+ final MtpObjectInfo placeholderObjectInfo =
+ manager.getObjectInfo(identifier.mDeviceId, identifier.mObjectHandle);
+
+ // Delete the target object info if it already exists (as a placeholder).
+ manager.deleteDocument(identifier.mDeviceId, identifier.mObjectHandle);
+
+ // Create the target object info with a correct file size and upload the file.
+ final long size = Os.lseek(mCacheFd.getFileDescriptor(), 0, OsConstants.SEEK_END);
+ final MtpObjectInfo targetObjectInfo = new MtpObjectInfo.Builder(placeholderObjectInfo)
+ .setCompressedSize(size)
+ .build();
+
+ Os.lseek(mCacheFd.getFileDescriptor(), 0, OsConstants.SEEK_SET);
+ final int newObjectHandle = manager.createDocument(
+ identifier.mDeviceId, targetObjectInfo, mCacheFd);
+
+ final MtpObjectInfo newObjectInfo = manager.getObjectInfo(
+ identifier.mDeviceId, newObjectHandle);
+ final Identifier parentIdentifier =
+ database.getParentIdentifier(identifier.mDocumentId);
+ database.updateObject(
+ identifier.mDocumentId,
+ identifier.mDeviceId,
+ parentIdentifier.mDocumentId,
+ operationsSupported,
+ newObjectInfo,
+ size);
+
+ mDirty = false;
+ }
+
+ @Override
+ public void close() throws IOException {
+ mCacheFd.close();
+ }
+}
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/PipeManager.java b/packages/MtpDocumentsProvider/src/com/android/mtp/PipeManager.java
index 1520f3b..795bbc1 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/PipeManager.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/PipeManager.java
@@ -16,13 +16,9 @@
package com.android.mtp;
-import android.content.Context;
-import android.mtp.MtpObjectInfo;
import android.os.ParcelFileDescriptor;
import android.util.Log;
-import java.io.File;
-import java.io.FileOutputStream;
import java.io.IOException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
@@ -52,15 +48,6 @@
return task.getReadingFileDescriptor();
}
- ParcelFileDescriptor writeDocument(Context context, MtpManager model, Identifier identifier,
- int[] operationsSupported)
- throws IOException {
- final Task task = new WriteDocumentTask(
- context, model, identifier, operationsSupported, mDatabase);
- mExecutor.execute(task);
- return task.getWritingFileDescriptor();
- }
-
ParcelFileDescriptor readThumbnail(MtpManager model, Identifier identifier) throws IOException {
final Task task = new GetThumbnailTask(model, identifier);
mExecutor.execute(task);
@@ -81,10 +68,6 @@
ParcelFileDescriptor getReadingFileDescriptor() {
return mDescriptors[0];
}
-
- ParcelFileDescriptor getWritingFileDescriptor() {
- return mDescriptors[1];
- }
}
private static class ImportFileTask extends Task {
@@ -108,85 +91,6 @@
}
}
- private static class WriteDocumentTask extends Task {
- private final Context mContext;
- private final MtpDatabase mDatabase;
- private final int[] mOperationsSupported;
-
- WriteDocumentTask(Context context,
- MtpManager model,
- Identifier identifier,
- int[] supportedOperations,
- MtpDatabase database)
- throws IOException {
- super(model, identifier);
- mContext = context;
- mDatabase = database;
- mOperationsSupported = supportedOperations;
- }
-
- @Override
- public void run() {
- File tempFile = null;
- try {
- // Obtain a temporary file and copy the data to it.
- tempFile = File.createTempFile("mtp", "tmp", mContext.getCacheDir());
- try (
- final FileOutputStream tempOutputStream =
- new ParcelFileDescriptor.AutoCloseOutputStream(
- ParcelFileDescriptor.open(
- tempFile, ParcelFileDescriptor.MODE_WRITE_ONLY));
- final ParcelFileDescriptor.AutoCloseInputStream inputStream =
- new ParcelFileDescriptor.AutoCloseInputStream(mDescriptors[0])
- ) {
- final byte[] buffer = new byte[32 * 1024];
- int bytes;
- while ((bytes = inputStream.read(buffer)) != -1) {
- mDescriptors[0].checkError();
- tempOutputStream.write(buffer, 0, bytes);
- }
- tempOutputStream.flush();
- }
-
- // Get the placeholder object info.
- final MtpObjectInfo placeholderObjectInfo =
- mManager.getObjectInfo(mIdentifier.mDeviceId, mIdentifier.mObjectHandle);
-
- // Delete the target object info if it already exists (as a placeholder).
- mManager.deleteDocument(mIdentifier.mDeviceId, mIdentifier.mObjectHandle);
-
- // Create the target object info with a correct file size and upload the file.
- final MtpObjectInfo targetObjectInfo =
- new MtpObjectInfo.Builder(placeholderObjectInfo)
- .setCompressedSize(tempFile.length())
- .build();
- final ParcelFileDescriptor tempInputDescriptor = ParcelFileDescriptor.open(
- tempFile, ParcelFileDescriptor.MODE_READ_ONLY);
- final int newObjectHandle = mManager.createDocument(
- mIdentifier.mDeviceId, targetObjectInfo, tempInputDescriptor);
-
- final MtpObjectInfo newObjectInfo = mManager.getObjectInfo(
- mIdentifier.mDeviceId, newObjectHandle);
- final Identifier parentIdentifier =
- mDatabase.getParentIdentifier(mIdentifier.mDocumentId);
- mDatabase.updateObject(
- mIdentifier.mDocumentId,
- mIdentifier.mDeviceId,
- parentIdentifier.mDocumentId,
- mOperationsSupported,
- newObjectInfo,
- tempFile.length());
- } catch (IOException error) {
- Log.w(MtpDocumentsProvider.TAG,
- "Failed to send a file because of: " + error.getMessage());
- } finally {
- if (tempFile != null) {
- tempFile.delete();
- }
- }
- }
- }
-
private static class GetThumbnailTask extends Task {
GetThumbnailTask(MtpManager model, Identifier identifier) throws IOException {
super(model, identifier);
diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/AppFuseTest.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/AppFuseTest.java
index 3b92506..e421de7 100644
--- a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/AppFuseTest.java
+++ b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/AppFuseTest.java
@@ -23,6 +23,8 @@
import android.test.AndroidTestCase;
import android.test.suitebuilder.annotation.MediumTest;
+import libcore.io.IoUtils;
+
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
@@ -143,7 +145,8 @@
}
@Override
- public int writeObjectBytes(int inode, long offset, int size, byte[] bytes) {
+ public int writeObjectBytes(
+ long fileHandle, int inode, long offset, int size, byte[] bytes) {
for (int i = 0; i < size; i++) {
resultBytes[(int)(offset + i)] = bytes[i];
}
@@ -152,7 +155,7 @@
});
appFuse.mount(storageManager);
final ParcelFileDescriptor fd = appFuse.openFile(
- INODE, ParcelFileDescriptor.MODE_WRITE_ONLY);
+ INODE, ParcelFileDescriptor.MODE_WRITE_ONLY | ParcelFileDescriptor.MODE_TRUNCATE);
try (final ParcelFileDescriptor.AutoCloseOutputStream stream =
new ParcelFileDescriptor.AutoCloseOutputStream(fd)) {
stream.write('a');
@@ -182,7 +185,7 @@
});
appFuse.mount(storageManager);
final ParcelFileDescriptor fd = appFuse.openFile(
- INODE, ParcelFileDescriptor.MODE_WRITE_ONLY);
+ INODE, ParcelFileDescriptor.MODE_WRITE_ONLY | ParcelFileDescriptor.MODE_TRUNCATE);
try (final ParcelFileDescriptor.AutoCloseOutputStream stream =
new ParcelFileDescriptor.AutoCloseOutputStream(fd)) {
stream.write('a');
@@ -192,6 +195,46 @@
appFuse.close();
}
+ public void testWriteFile_flushError() throws IOException {
+ final StorageManager storageManager = getContext().getSystemService(StorageManager.class);
+ final int INODE = 10;
+ final AppFuse appFuse = new AppFuse(
+ "test",
+ new TestCallback() {
+ @Override
+ public long getFileSize(int inode) throws FileNotFoundException {
+ if (inode != INODE) {
+ throw new FileNotFoundException();
+ }
+ return 5;
+ }
+
+ @Override
+ public int writeObjectBytes(
+ long fileHandle, int inode, long offset, int size, byte[] bytes) {
+ return size;
+ }
+
+ @Override
+ public void flushFileHandle(long fileHandle) throws IOException {
+ throw new IOException();
+ }
+ });
+ appFuse.mount(storageManager);
+ final ParcelFileDescriptor fd = appFuse.openFile(
+ INODE, ParcelFileDescriptor.MODE_WRITE_ONLY | ParcelFileDescriptor.MODE_TRUNCATE);
+ try (final ParcelFileDescriptor.AutoCloseOutputStream stream =
+ new ParcelFileDescriptor.AutoCloseOutputStream(fd)) {
+ stream.write('a');
+ try {
+ IoUtils.close(fd.getFileDescriptor());
+ fail();
+ } catch (IOException e) {
+ }
+ }
+ appFuse.close();
+ }
+
private static class TestCallback implements AppFuse.Callback {
@Override
public long getFileSize(int inode) throws FileNotFoundException {
@@ -205,9 +248,15 @@
}
@Override
- public int writeObjectBytes(int inode, long offset, int size, byte[] bytes)
+ public int writeObjectBytes(long fileHandle, int inode, long offset, int size, byte[] bytes)
throws IOException {
throw new IOException();
}
+
+ @Override
+ public void flushFileHandle(long fileHandle) throws IOException {}
+
+ @Override
+ public void closeFileHandle(long fileHandle) {}
}
}
diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDocumentsProviderTest.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDocumentsProviderTest.java
index 0de761c..9ed15c8 100644
--- a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDocumentsProviderTest.java
+++ b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDocumentsProviderTest.java
@@ -21,6 +21,7 @@
import android.mtp.MtpObjectInfo;
import android.net.Uri;
import android.os.ParcelFileDescriptor;
+import android.os.ParcelFileDescriptor.AutoCloseOutputStream;
import android.os.storage.StorageManager;
import android.provider.DocumentsContract.Document;
import android.provider.DocumentsContract.Root;
@@ -533,6 +534,30 @@
}
}
+ public void testOpenDocument_writing() throws Exception {
+ setupProvider(MtpDatabaseConstants.FLAG_DATABASE_IN_MEMORY);
+ setupRoots(0, new MtpRoot[] {
+ new MtpRoot(0, 0, "Storage", 0, 0, "")
+ });
+ final String documentId = mProvider.createDocument("2", "text/plain", "test.txt");
+ {
+ final ParcelFileDescriptor fd = mProvider.openDocument(documentId, "w", null);
+ try (ParcelFileDescriptor.AutoCloseOutputStream stream =
+ new ParcelFileDescriptor.AutoCloseOutputStream(fd)) {
+ stream.write("Hello".getBytes());
+ }
+ }
+ {
+ final ParcelFileDescriptor fd = mProvider.openDocument(documentId, "r", null);
+ try (ParcelFileDescriptor.AutoCloseInputStream stream =
+ new ParcelFileDescriptor.AutoCloseInputStream(fd)) {
+ final byte[] bytes = new byte[5];
+ stream.read(bytes);
+ assertTrue(Arrays.equals("Hello".getBytes(), bytes));
+ }
+ }
+ }
+
public void testBusyDevice() throws Exception {
mMtpManager = new TestMtpManager(getContext()) {
@Override
@@ -740,6 +765,7 @@
mProvider = new MtpDocumentsProvider();
final StorageManager storageManager = getContext().getSystemService(StorageManager.class);
assertTrue(mProvider.onCreateForTesting(
+ getContext(),
mResources,
mMtpManager,
mResolver,
diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/PipeManagerTest.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/PipeManagerTest.java
index 8611797..53dc3db 100644
--- a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/PipeManagerTest.java
+++ b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/PipeManagerTest.java
@@ -16,10 +16,7 @@
package com.android.mtp;
-import android.database.Cursor;
-import android.mtp.MtpObjectInfo;
import android.os.ParcelFileDescriptor;
-import android.provider.DocumentsContract.Document;
import android.test.AndroidTestCase;
import android.test.suitebuilder.annotation.MediumTest;
@@ -66,64 +63,6 @@
assertDescriptorError(descriptor);
}
- public void testWriteDocument_basic() throws Exception {
- TestUtil.addTestDevice(mDatabase);
- TestUtil.addTestStorage(mDatabase, "1");
-
- final MtpObjectInfo info =
- new MtpObjectInfo.Builder().setObjectHandle(1).setName("note.txt").build();
- mDatabase.getMapper().startAddingDocuments("2");
- mDatabase.getMapper().putChildDocuments(
- 0, "2", TestUtil.OPERATIONS_SUPPORTED,
- new MtpObjectInfo[] { info },
- new long[] { 0L });
- mDatabase.getMapper().stopAddingDocuments("2");
- // Create a placeholder file which should be replaced by a real file later.
- mtpManager.setObjectInfo(0, info);
-
- // Upload testing bytes.
- final ParcelFileDescriptor descriptor = mPipeManager.writeDocument(
- getContext(),
- mtpManager,
- new Identifier(0, 0, 1, "2", MtpDatabaseConstants.DOCUMENT_TYPE_OBJECT),
- TestUtil.OPERATIONS_SUPPORTED);
- final ParcelFileDescriptor.AutoCloseOutputStream outputStream =
- new ParcelFileDescriptor.AutoCloseOutputStream(descriptor);
- outputStream.write(HELLO_BYTES, 0, HELLO_BYTES.length);
- outputStream.close();
- mExecutor.shutdown();
- assertTrue(mExecutor.awaitTermination(1000, TimeUnit.MILLISECONDS));
-
- // Check if the placeholder file is removed.
- try {
- mtpManager.getObjectInfo(0, 1);
- fail(); // The placeholder file has not been deleted.
- } catch (IOException e) {
- // Expected error, as the file is gone.
- }
-
- // Confirm that the target file is created.
- final MtpObjectInfo targetDocument = mtpManager.getObjectInfo(
- 0, TestMtpManager.CREATED_DOCUMENT_HANDLE);
- assertTrue(targetDocument != null);
-
- // Confirm the object handle is updated.
- try (final Cursor cursor = mDatabase.queryDocument(
- "2", new String[] { MtpDatabaseConstants.COLUMN_OBJECT_HANDLE })) {
- assertEquals(1, cursor.getCount());
- cursor.moveToNext();
- assertEquals(TestMtpManager.CREATED_DOCUMENT_HANDLE, cursor.getInt(0));
- }
-
- // Verify uploaded bytes.
- final byte[] uploadedBytes = mtpManager.getImportFileBytes(
- 0, TestMtpManager.CREATED_DOCUMENT_HANDLE);
- assertEquals(HELLO_BYTES.length, uploadedBytes.length);
- for (int i = 0; i < HELLO_BYTES.length; i++) {
- assertEquals(HELLO_BYTES[i], uploadedBytes[i]);
- }
- }
-
public void testReadThumbnail_basic() throws Exception {
mtpManager.setThumbnail(0, 1, HELLO_BYTES);
final ParcelFileDescriptor descriptor = mPipeManager.readThumbnail(
diff --git a/packages/PrintServiceRecommendationService/Android.mk b/packages/PrintServiceRecommendationService/Android.mk
new file mode 100644
index 0000000..66cb057
--- /dev/null
+++ b/packages/PrintServiceRecommendationService/Android.mk
@@ -0,0 +1,29 @@
+# Copyright (C) 2016 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_PACKAGE_NAME := PrintRecommendationService
+
+include $(BUILD_PACKAGE)
+
+LOCAL_SDK_VERSION := system_current
+
+include $(call all-makefiles-under, $(LOCAL_PATH))
diff --git a/packages/PrintServiceRecommendationService/AndroidManifest.xml b/packages/PrintServiceRecommendationService/AndroidManifest.xml
new file mode 100644
index 0000000..0eb218c
--- /dev/null
+++ b/packages/PrintServiceRecommendationService/AndroidManifest.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * Copyright (c) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.printservice.recommendation">
+
+ <uses-permission android:name="android.permission.INTERNET" />
+
+ <application
+ android:allowClearUserData="false"
+ android:label="@string/app_label"
+ android:allowBackup= "false">
+
+ <service
+ android:name=".RecommendationServiceImpl"
+ android:permission="android.permission.BIND_PRINT_RECOMMENDATION_SERVICE">
+
+ <intent-filter>
+ <action android:name="android.printservice.recommendation.RecommendationService" />
+ </intent-filter>
+ </service>
+
+ </application>
+
+</manifest>
diff --git a/packages/PrintServiceRecommendationService/MODULE_LICENSE_APACHE2 b/packages/PrintServiceRecommendationService/MODULE_LICENSE_APACHE2
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/packages/PrintServiceRecommendationService/MODULE_LICENSE_APACHE2
diff --git a/packages/PrintServiceRecommendationService/NOTICE b/packages/PrintServiceRecommendationService/NOTICE
new file mode 100644
index 0000000..c5b1efa
--- /dev/null
+++ b/packages/PrintServiceRecommendationService/NOTICE
@@ -0,0 +1,190 @@
+
+ Copyright (c) 2005-2008, 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.
+
+ 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.
+
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
diff --git a/packages/PrintServiceRecommendationService/res/values/donottranslate.xml b/packages/PrintServiceRecommendationService/res/values/donottranslate.xml
new file mode 100644
index 0000000..4cf0eaf
--- /dev/null
+++ b/packages/PrintServiceRecommendationService/res/values/donottranslate.xml
@@ -0,0 +1,18 @@
+<?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.
+-->
+<resources>
+ <string name="app_label">Print Service Recommendation Service</string>
+</resources>
diff --git a/packages/PrintServiceRecommendationService/res/values/strings.xml b/packages/PrintServiceRecommendationService/res/values/strings.xml
new file mode 100644
index 0000000..83d3800
--- /dev/null
+++ b/packages/PrintServiceRecommendationService/res/values/strings.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ (c) Copyright 2016 Mopria Alliance, Inc.
+ (c) 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.
+-->
+
+<resources>
+ <string name="plugin_vendor_hp">HP</string>
+ <string name="plugin_vendor_lexmark">Lexmark</string>
+ <string name="plugin_vendor_brother">Brother</string>
+ <string name="plugin_vendor_canon">Canon</string>
+ <string name="plugin_vendor_xerox">Xerox</string>
+ <string name="plugin_vendor_samsung">Samsung Electorics</string>
+ <string name="plugin_vendor_epson">Epson</string>
+ <string name="plugin_vendor_konika_minolta">Konika Minolta</string>
+ <string name="plugin_vendor_fuji">Fuji</string>
+</resources>
diff --git a/packages/PrintServiceRecommendationService/res/xml/vendorconfigs.xml b/packages/PrintServiceRecommendationService/res/xml/vendorconfigs.xml
new file mode 100644
index 0000000..fda2768
--- /dev/null
+++ b/packages/PrintServiceRecommendationService/res/xml/vendorconfigs.xml
@@ -0,0 +1,96 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ (c) 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.
+ -->
+
+<vendors>
+ <vendor>
+ <name>@string/plugin_vendor_hp</name>
+ <package>com.hp.android.printservice</package>
+ <mdns-names>
+ <mdns-name>HP</mdns-name>
+ <mdns-name>Hewlett-Packard</mdns-name>
+ <mdns-name>Hewlett Packard</mdns-name>
+ </mdns-names>
+ </vendor>
+
+ <vendor>
+ <name>@string/plugin_vendor_lexmark</name>
+ <package>com.lexmark.print.plugin</package>
+ <mdns-names>
+ <mdns-name>Lexmark</mdns-name>
+ <mdns-name>Lexmark International</mdns-name>
+ </mdns-names>
+ </vendor>
+
+ <vendor>
+ <name>@string/plugin_vendor_brother</name>
+ <package>com.brother.printservice</package>
+ <mdns-names>
+ <mdns-name>Brother</mdns-name>
+ </mdns-names>
+ </vendor>
+
+ <vendor>
+ <name>@string/plugin_vendor_canon</name>
+ <package>com.xerox.printservice</package>
+ <mdns-names>
+ <mdns-name>Canon</mdns-name>
+ </mdns-names>
+ </vendor>
+
+ <vendor>
+ <name>@string/plugin_vendor_xerox</name>
+ <package>jp.co.canon.android.printservice.plugin</package>
+ <mdns-names>
+ <mdns-name>Xerox</mdns-name>
+ </mdns-names>
+ </vendor>
+
+ <vendor>
+ <name>@string/plugin_vendor_samsung</name>
+ <package>com.sec.app.samsungprintservice</package>
+ <mdns-names>
+ <mdns-name>Samsung</mdns-name>
+ </mdns-names>
+ </vendor>
+
+ <vendor>
+ <name>@string/plugin_vendor_epson</name>
+ <package>com.epson.mobilephone.android.epsonprintserviceplugin</package>
+ <mdns-names>
+ <mdns-name>Epson</mdns-name>
+ </mdns-names>
+ </vendor>
+
+ <vendor>
+ <name>@string/plugin_vendor_konika_minolta</name>
+ <package>com.kmbt.printservice</package>
+ <mdns-names>
+ <mdns-name>kmkmkm</mdns-name>
+ <mdns-name>Konica Minolta</mdns-name>
+ <mdns-name>Minolta</mdns-name>
+ </mdns-names>
+ </vendor>
+
+ <vendor>
+ <name>@string/plugin_vendor_fuji</name>
+ <package>jp.co.fujixerox.prt.PrintUtil.PCL</package>
+ <mdns-names>
+ <mdns-name>FUJI XEROX</mdns-name>
+ </mdns-names>
+ </vendor>
+</vendors>
diff --git a/packages/PrintServiceRecommendationService/src/com/android/printservice/recommendation/PrintServicePlugin.java b/packages/PrintServiceRecommendationService/src/com/android/printservice/recommendation/PrintServicePlugin.java
new file mode 100644
index 0000000..d604ef8
--- /dev/null
+++ b/packages/PrintServiceRecommendationService/src/com/android/printservice/recommendation/PrintServicePlugin.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.printservice.recommendation;
+
+import android.annotation.IntRange;
+import android.annotation.NonNull;
+import android.annotation.StringRes;
+
+/**
+ * Interface to be implemented by each print service plugin.
+ * <p/>
+ * A print service plugin is a minimal version of a real {@link android.printservice.PrintService
+ * print service}. You cannot print using the plugin. The only functionality in the plugin is to
+ * report the number of printers that the real service would discover.
+ */
+public interface PrintServicePlugin {
+ /**
+ * Call back used by the print service plugins.
+ */
+ interface PrinterDiscoveryCallback {
+ /**
+ * Announce that something changed and the UI for this plugin should be updated.
+ *
+ * @param numDiscoveredPrinters The number of printers discovered.
+ */
+ void onChanged(@IntRange(from = 0) int numDiscoveredPrinters);
+ }
+
+ /**
+ * Get the name (a string reference) of the {@link android.printservice.PrintService print
+ * service} with the {@link #getPackageName specified package name}. This is read once, hence
+ * returning different data at different times is not allowed.
+ *
+ * @return The name of the print service as a string reference. The localization is handled
+ * outside of the plugin.
+ */
+ @StringRes int getName();
+
+ /**
+ * The package name of the full print service.
+ *
+ * @return The package name
+ */
+ @NonNull CharSequence getPackageName();
+
+ /**
+ * Start the discovery plugin.
+ *
+ * @param callback Callbacks used by this plugin.
+ *
+ * @throws Exception If anything went wrong when starting the plugin
+ */
+ void start(@NonNull PrinterDiscoveryCallback callback) throws Exception;
+
+ /**
+ * Stop the plugin. This can only return once the plugin is completely finished and cleaned up.
+ *
+ * @throws Exception If anything went wrong while stopping plugin
+ */
+ void stop() throws Exception;
+}
diff --git a/packages/PrintServiceRecommendationService/src/com/android/printservice/recommendation/RecommendationServiceImpl.java b/packages/PrintServiceRecommendationService/src/com/android/printservice/recommendation/RecommendationServiceImpl.java
new file mode 100644
index 0000000..9f6dad8
--- /dev/null
+++ b/packages/PrintServiceRecommendationService/src/com/android/printservice/recommendation/RecommendationServiceImpl.java
@@ -0,0 +1,110 @@
+/*
+ * 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.printservice.recommendation;
+
+import android.content.res.Configuration;
+import android.printservice.recommendation.RecommendationInfo;
+import android.printservice.recommendation.RecommendationService;
+import android.printservice.PrintService;
+import android.util.Log;
+import com.android.printservice.recommendation.plugin.mdnsFilter.MDNSFilterPlugin;
+import com.android.printservice.recommendation.plugin.mdnsFilter.VendorConfig;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+import java.util.ArrayList;
+
+/**
+ * Service that recommends {@link PrintService print services} that might be a good idea to install.
+ */
+public class RecommendationServiceImpl extends RecommendationService
+ implements RemotePrintServicePlugin.OnChangedListener {
+ private static final String LOG_TAG = "PrintServiceRecService";
+
+ /** All registered plugins */
+ private ArrayList<RemotePrintServicePlugin> mPlugins;
+
+ @Override
+ public void onConnected() {
+ mPlugins = new ArrayList<>();
+
+ try {
+ for (VendorConfig config : VendorConfig.getAllConfigs(this)) {
+ try {
+ mPlugins.add(new RemotePrintServicePlugin(new MDNSFilterPlugin(this,
+ config.name, config.packageName, config.mDNSNames), this, false));
+ } catch (Exception e) {
+ Log.e(LOG_TAG, "Could not initiate simple MDNS plugin for " +
+ config.packageName, e);
+ }
+ }
+ } catch (IOException | XmlPullParserException e) {
+ new RuntimeException("Could not parse vendorconfig", e);
+ }
+
+ final int numPlugins = mPlugins.size();
+ for (int i = 0; i < numPlugins; i++) {
+ try {
+ mPlugins.get(i).start();
+ } catch (RemotePrintServicePlugin.PluginException e) {
+ Log.e(LOG_TAG, "Could not start plugin", e);
+ }
+ }
+ }
+
+ @Override
+ public void onDisconnected() {
+ final int numPlugins = mPlugins.size();
+ for (int i = 0; i < numPlugins; i++) {
+ try {
+ mPlugins.get(i).stop();
+ } catch (RemotePrintServicePlugin.PluginException e) {
+ Log.e(LOG_TAG, "Could not stop plugin", e);
+ }
+ }
+ }
+
+ @Override
+ public void onConfigurationChanged(Configuration newConfig) {
+ // Need to update plugin names as they might be localized
+ onChanged();
+ }
+
+ @Override
+ public void onChanged() {
+ ArrayList<RecommendationInfo> recommendations = new ArrayList<>();
+
+ final int numPlugins = mPlugins.size();
+ for (int i = 0; i < numPlugins; i++) {
+ RemotePrintServicePlugin plugin = mPlugins.get(i);
+
+ try {
+ int numPrinters = plugin.getNumPrinters();
+
+ if (numPrinters > 0) {
+ recommendations.add(new RecommendationInfo(plugin.packageName,
+ getString(plugin.name), numPrinters,
+ plugin.recommendsMultiVendorService));
+ }
+ } catch (Exception e) {
+ Log.e(LOG_TAG, "Could not read state of plugin for " + plugin.packageName, e);
+ }
+ }
+
+ updateRecommendations(recommendations);
+ }
+}
diff --git a/packages/PrintServiceRecommendationService/src/com/android/printservice/recommendation/RemotePrintServicePlugin.java b/packages/PrintServiceRecommendationService/src/com/android/printservice/recommendation/RemotePrintServicePlugin.java
new file mode 100644
index 0000000..dbd1649
--- /dev/null
+++ b/packages/PrintServiceRecommendationService/src/com/android/printservice/recommendation/RemotePrintServicePlugin.java
@@ -0,0 +1,152 @@
+/*
+ * 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.printservice.recommendation;
+
+import android.annotation.IntRange;
+import android.annotation.NonNull;
+import android.annotation.StringRes;
+import com.android.internal.util.Preconditions;
+
+/**
+ * Wrapper for a {@link PrintServicePlugin}, isolating issues with the plugin as good as possible
+ * from the {@link RecommendationServiceImpl service}.
+ */
+class RemotePrintServicePlugin implements PrintServicePlugin.PrinterDiscoveryCallback {
+ /** Lock for this object */
+ private final Object mLock = new Object();
+
+ /** The name of the print service. */
+ public final @StringRes int name;
+
+ /** If the print service if for more than a single vendor */
+ public final boolean recommendsMultiVendorService;
+
+ /** The package name of the full print service */
+ public final @NonNull CharSequence packageName;
+
+ /** Wrapped plugin */
+ private final @NonNull PrintServicePlugin mPlugin;
+
+ /** The number of printers discovered by the plugin */
+ private @IntRange(from = 0) int mNumPrinters;
+
+ /** If the plugin is started by not yet stopped */
+ private boolean isRunning;
+
+ /** Listener for changes to {@link #mNumPrinters}. */
+ private @NonNull OnChangedListener mListener;
+
+ /**
+ * Create a new remote for a {@link PrintServicePlugin plugin}.
+ *
+ * @param plugin The plugin to be wrapped
+ * @param listener The listener to be notified about changes in this plugin
+ * @param recommendsMultiVendorService If the plugin detects printers of more than a single
+ * vendor
+ *
+ * @throws PluginException If the plugin has issues while caching basic stub properties
+ */
+ public RemotePrintServicePlugin(@NonNull PrintServicePlugin plugin,
+ @NonNull OnChangedListener listener, boolean recommendsMultiVendorService)
+ throws PluginException {
+ mListener = listener;
+ mPlugin = plugin;
+ this.recommendsMultiVendorService = recommendsMultiVendorService;
+
+ // We handle any throwable to isolate our self from bugs in the plugin code.
+ // Cache simple properties to avoid having to deal with exceptions later in the code.
+ try {
+ name = Preconditions.checkArgumentPositive(mPlugin.getName(), "name");
+ packageName = Preconditions.checkStringNotEmpty(mPlugin.getPackageName(),
+ "packageName");
+ } catch (Throwable e) {
+ throw new PluginException(mPlugin, "Cannot cache simple properties ", e);
+ }
+
+ isRunning = false;
+ }
+
+ /**
+ * Start the plugin. From now on there might be callbacks to the registered listener.
+ */
+ public void start()
+ throws PluginException {
+ // We handle any throwable to isolate our self from bugs in the stub code
+ try {
+ synchronized (mLock) {
+ isRunning = true;
+ mPlugin.start(this);
+ }
+ } catch (Throwable e) {
+ throw new PluginException(mPlugin, "Cannot start", e);
+ }
+ }
+
+ /**
+ * Stop the plugin. From this call on there will not be any more callbacks.
+ */
+ public void stop() throws PluginException {
+ // We handle any throwable to isolate our self from bugs in the stub code
+ try {
+ synchronized (mLock) {
+ mPlugin.stop();
+ isRunning = false;
+ }
+ } catch (Throwable e) {
+ throw new PluginException(mPlugin, "Cannot stop", e);
+ }
+ }
+
+ /**
+ * Get the current number of printers reported by the stub.
+ *
+ * @return The number of printers reported by the stub.
+ */
+ public @IntRange(from = 0) int getNumPrinters() {
+ return mNumPrinters;
+ }
+
+ @Override
+ public void onChanged(@IntRange(from = 0) int numDiscoveredPrinters) {
+ synchronized (mLock) {
+ Preconditions.checkState(isRunning);
+
+ mNumPrinters = Preconditions.checkArgumentNonnegative(numDiscoveredPrinters,
+ "numDiscoveredPrinters");
+
+ if (mNumPrinters > 0) {
+ mListener.onChanged();
+ }
+ }
+ }
+
+ /**
+ * Listener to listen for changes to {@link #getNumPrinters}
+ */
+ public interface OnChangedListener {
+ void onChanged();
+ }
+
+ /**
+ * Exception thrown if the stub has any issues.
+ */
+ public class PluginException extends Exception {
+ private PluginException(PrintServicePlugin plugin, String message, Throwable e) {
+ super(plugin + ": " + message, e);
+ }
+ }
+}
diff --git a/packages/PrintServiceRecommendationService/src/com/android/printservice/recommendation/plugin/mdnsFilter/MDNSFilterPlugin.java b/packages/PrintServiceRecommendationService/src/com/android/printservice/recommendation/plugin/mdnsFilter/MDNSFilterPlugin.java
new file mode 100644
index 0000000..26300b1
--- /dev/null
+++ b/packages/PrintServiceRecommendationService/src/com/android/printservice/recommendation/plugin/mdnsFilter/MDNSFilterPlugin.java
@@ -0,0 +1,199 @@
+/*
+ * 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.printservice.recommendation.plugin.mdnsFilter;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.StringRes;
+import android.content.Context;
+import android.net.nsd.NsdManager;
+import android.net.nsd.NsdServiceInfo;
+import android.util.Log;
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.util.Preconditions;
+import com.android.printservice.recommendation.PrintServicePlugin;
+import com.android.printservice.recommendation.util.MDNSUtils;
+import com.android.printservice.recommendation.util.NsdResolveQueue;
+
+import java.util.HashSet;
+import java.util.List;
+
+/**
+ * A plugin listening for mDNS results and only adding the ones that {@link
+ * MDNSUtils#isVendorPrinter match} configured list
+ */
+public class MDNSFilterPlugin implements PrintServicePlugin, NsdManager.DiscoveryListener {
+ private static final String LOG_TAG = "MDNSFilterPlugin";
+
+ private static final String PRINTER_SERVICE_TYPE = "_ipp._tcp";
+
+ /** Name of the print service this plugin is for */
+ private final @StringRes int mName;
+
+ /** Package name of the print service this plugin is for */
+ private final @NonNull CharSequence mPackageName;
+
+ /** mDNS names handled by the print service this plugin is for */
+ private final @NonNull HashSet<String> mMDNSNames;
+
+ /** Printer identifiers of the mPrinters found. */
+ @GuardedBy("mLock")
+ private final @NonNull HashSet<String> mPrinters;
+
+ /** Context of the user of this plugin */
+ private final @NonNull Context mContext;
+
+ /**
+ * Call back to report the number of mPrinters found.
+ *
+ * We assume that {@link #start} and {@link #stop} are never called in parallel, hence it is
+ * safe to not synchronize access to this field.
+ */
+ private @Nullable PrinterDiscoveryCallback mCallback;
+
+ /** Queue used to resolve nsd infos */
+ private final @NonNull NsdResolveQueue mResolveQueue;
+
+ /**
+ * Create new stub that assumes that a print service can be used to print on all mPrinters
+ * matching some mDNS names.
+ *
+ * @param context The context the plugin runs in
+ * @param name The user friendly name of the print service
+ * @param packageName The package name of the print service
+ * @param mDNSNames The mDNS names of the printer.
+ */
+ public MDNSFilterPlugin(@NonNull Context context, @NonNull String name,
+ @NonNull CharSequence packageName, @NonNull List<String> mDNSNames) {
+ mContext = Preconditions.checkNotNull(context, "context");
+ mName = mContext.getResources().getIdentifier(Preconditions.checkStringNotEmpty(name,
+ "name"), null, mContext.getPackageName());
+ mPackageName = Preconditions.checkStringNotEmpty(packageName);
+ mMDNSNames = new HashSet<>(Preconditions
+ .checkCollectionNotEmpty(Preconditions.checkCollectionElementsNotNull(mDNSNames,
+ "mDNSNames"), "mDNSNames"));
+
+ mResolveQueue = NsdResolveQueue.getInstance();
+ mPrinters = new HashSet<>();
+ }
+
+ @Override
+ public @NonNull CharSequence getPackageName() {
+ return mPackageName;
+ }
+
+ /**
+ * @return The NDS manager
+ */
+ private NsdManager getNDSManager() {
+ return (NsdManager) mContext.getSystemService(Context.NSD_SERVICE);
+ }
+
+ @Override
+ public void start(@NonNull PrinterDiscoveryCallback callback) throws Exception {
+ mCallback = callback;
+
+ getNDSManager().discoverServices(PRINTER_SERVICE_TYPE, NsdManager.PROTOCOL_DNS_SD,
+ this);
+ }
+
+ @Override
+ public @StringRes int getName() {
+ return mName;
+ }
+
+ @Override
+ public void stop() throws Exception {
+ mCallback.onChanged(0);
+ mCallback = null;
+
+ getNDSManager().stopServiceDiscovery(this);
+ }
+
+ @Override
+ public void onStartDiscoveryFailed(String serviceType, int errorCode) {
+ Log.w(LOG_TAG, "Failed to start network discovery for type " + serviceType + ": "
+ + errorCode);
+ }
+
+ @Override
+ public void onStopDiscoveryFailed(String serviceType, int errorCode) {
+ Log.w(LOG_TAG, "Failed to stop network discovery for type " + serviceType + ": "
+ + errorCode);
+ }
+
+ @Override
+ public void onDiscoveryStarted(String serviceType) {
+ // empty
+ }
+
+ @Override
+ public void onDiscoveryStopped(String serviceType) {
+ mPrinters.clear();
+ }
+
+ @Override
+ public void onServiceFound(NsdServiceInfo serviceInfo) {
+ mResolveQueue.resolve(getNDSManager(), serviceInfo,
+ new NsdManager.ResolveListener() {
+ @Override
+ public void onResolveFailed(NsdServiceInfo serviceInfo, int errorCode) {
+ Log.w(LOG_TAG, "Service found: could not resolve " + serviceInfo + ": " +
+ errorCode);
+ }
+
+ @Override
+ public void onServiceResolved(NsdServiceInfo serviceInfo) {
+ if (MDNSUtils.isVendorPrinter(serviceInfo, mMDNSNames)) {
+ if (mCallback != null) {
+ boolean added = mPrinters.add(serviceInfo.getHost().getHostAddress());
+
+ if (added) {
+ mCallback.onChanged(mPrinters.size());
+ }
+ }
+ }
+ }
+ });
+ }
+
+ @Override
+ public void onServiceLost(NsdServiceInfo serviceInfo) {
+ mResolveQueue.resolve(getNDSManager(), serviceInfo,
+ new NsdManager.ResolveListener() {
+ @Override
+ public void onResolveFailed(NsdServiceInfo serviceInfo, int errorCode) {
+ Log.w(LOG_TAG, "Service lost: Could not resolve " + serviceInfo + ": "
+ + errorCode);
+ }
+
+ @Override
+ public void onServiceResolved(NsdServiceInfo serviceInfo) {
+ if (MDNSUtils.isVendorPrinter(serviceInfo, mMDNSNames)) {
+ if (mCallback != null) {
+ boolean removed = mPrinters
+ .remove(serviceInfo.getHost().getHostAddress());
+
+ if (removed) {
+ mCallback.onChanged(mPrinters.size());
+ }
+ }
+ }
+ }
+ });
+ }
+}
diff --git a/packages/PrintServiceRecommendationService/src/com/android/printservice/recommendation/plugin/mdnsFilter/VendorConfig.java b/packages/PrintServiceRecommendationService/src/com/android/printservice/recommendation/plugin/mdnsFilter/VendorConfig.java
new file mode 100644
index 0000000..57d5c71
--- /dev/null
+++ b/packages/PrintServiceRecommendationService/src/com/android/printservice/recommendation/plugin/mdnsFilter/VendorConfig.java
@@ -0,0 +1,325 @@
+/*
+ * 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.printservice.recommendation.plugin.mdnsFilter;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.Context;
+import android.content.res.XmlResourceParser;
+import android.util.ArrayMap;
+import com.android.internal.annotations.Immutable;
+import com.android.internal.util.Preconditions;
+import com.android.printservice.recommendation.R;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Vendor configuration as read from {@link R.xml#vendorconfigs vendorconfigs.xml}. Configuration
+ * can be read via {@link #getConfig(Context, String)}.
+ */
+@Immutable
+public class VendorConfig {
+ /** Lock for {@link #sConfigs} */
+ private static final Object sLock = new Object();
+
+ /** Strings used as XML tags */
+ private static final String VENDORS_TAG = "vendors";
+ private static final String VENDOR_TAG = "vendor";
+ private static final String NAME_TAG = "name";
+ private static final String PACKAGE_TAG = "package";
+ private static final String MDNSNAMES_TAG = "mdns-names";
+ private static final String MDNSNAME_TAG = "mdns-name";
+
+ /** Map from vendor name to config. Initialized on first {@link #getConfig use}. */
+ private static @Nullable ArrayMap<String, VendorConfig> sConfigs;
+
+ /** Localized vendor name */
+ public final @NonNull String name;
+
+ /** Package name containing the print service for this vendor */
+ public final @NonNull String packageName;
+
+ /** mDNS names used by this vendor */
+ public final @NonNull List<String> mDNSNames;
+
+ /**
+ * Create an immutable configuration.
+ */
+ private VendorConfig(@NonNull String name, @NonNull String packageName,
+ @NonNull List<String> mDNSNames) {
+ this.name = Preconditions.checkStringNotEmpty(name);
+ this.packageName = Preconditions.checkStringNotEmpty(packageName);
+ this.mDNSNames = Preconditions.checkCollectionElementsNotNull(mDNSNames, "mDNSName");
+ }
+
+ /**
+ * Get the configuration for a vendor.
+ *
+ * @param context Calling context
+ * @param name The name of the config to read
+ *
+ * @return the config for the vendor or null if not found
+ *
+ * @throws IOException
+ * @throws XmlPullParserException
+ */
+ public static @Nullable VendorConfig getConfig(@NonNull Context context, @NonNull String name)
+ throws IOException, XmlPullParserException {
+ synchronized (sLock) {
+ if (sConfigs == null) {
+ sConfigs = readVendorConfigs(context);
+ }
+
+ return sConfigs.get(name);
+ }
+ }
+
+ /**
+ * Get all known vendor configurations.
+ *
+ * @param context Calling context
+ *
+ * @return The known configurations
+ *
+ * @throws IOException
+ * @throws XmlPullParserException
+ */
+ public static @NonNull Collection<VendorConfig> getAllConfigs(@NonNull Context context)
+ throws IOException, XmlPullParserException {
+ synchronized (sLock) {
+ if (sConfigs == null) {
+ sConfigs = readVendorConfigs(context);
+ }
+
+ return sConfigs.values();
+ }
+ }
+
+ /**
+ * Read the text from a XML tag.
+ *
+ * @param parser XML parser to read from
+ *
+ * @return The text or "" if no text was found
+ *
+ * @throws IOException
+ * @throws XmlPullParserException
+ */
+ private static @NonNull String readText(XmlPullParser parser)
+ throws IOException, XmlPullParserException {
+ String result = "";
+
+ if (parser.next() == XmlPullParser.TEXT) {
+ result = parser.getText();
+ parser.nextTag();
+ }
+
+ return result;
+ }
+
+ /**
+ * Read a tag with a text content from the parser.
+ *
+ * @param parser XML parser to read from
+ * @param tagName The name of the tag to read
+ *
+ * @return The text content of the tag
+ *
+ * @throws IOException
+ * @throws XmlPullParserException
+ */
+ private static @NonNull String readSimpleTag(@NonNull Context context,
+ @NonNull XmlPullParser parser, @NonNull String tagName, boolean resolveReferences)
+ throws IOException, XmlPullParserException {
+ parser.require(XmlPullParser.START_TAG, null, tagName);
+ String text = readText(parser);
+ parser.require(XmlPullParser.END_TAG, null, tagName);
+
+ if (resolveReferences && text.startsWith("@")) {
+ return context.getResources().getString(
+ context.getResources().getIdentifier(text, null, context.getPackageName()));
+ } else {
+ return text;
+ }
+ }
+
+ /**
+ * Read content of a list of tags.
+ *
+ * @param parser XML parser to read from
+ * @param tagName The name of the list tag
+ * @param subTagName The name of the list-element tags
+ * @param tagReader The {@link TagReader reader} to use to read the tag content
+ * @param <T> The type of the parsed tag content
+ *
+ * @return A list of {@link T}
+ *
+ * @throws XmlPullParserException
+ * @throws IOException
+ */
+ private static @NonNull <T> ArrayList<T> readTagList(@NonNull XmlPullParser parser,
+ @NonNull String tagName, @NonNull String subTagName, @NonNull TagReader<T> tagReader)
+ throws XmlPullParserException, IOException {
+ ArrayList<T> entries = new ArrayList<>();
+
+ parser.require(XmlPullParser.START_TAG, null, tagName);
+ while (parser.next() != XmlPullParser.END_TAG) {
+ if (parser.getEventType() != XmlPullParser.START_TAG) {
+ continue;
+ }
+
+ if (parser.getName().equals(subTagName)) {
+ entries.add(tagReader.readTag(parser, subTagName));
+ } else {
+ throw new XmlPullParserException(
+ "Unexpected subtag of " + tagName + ": " + parser.getName());
+ }
+ }
+
+ return entries;
+ }
+
+ /**
+ * Read the vendor configuration file.
+ *
+ * @param context The content issuing the read
+ *
+ * @return An map pointing from vendor name to config
+ *
+ * @throws IOException
+ * @throws XmlPullParserException
+ */
+ private static @NonNull ArrayMap<String, VendorConfig> readVendorConfigs(
+ @NonNull final Context context) throws IOException, XmlPullParserException {
+ try (XmlResourceParser parser = context.getResources().getXml(R.xml.vendorconfigs)) {
+ // Skip header
+ int parsingEvent;
+ do {
+ parsingEvent = parser.next();
+ } while (parsingEvent != XmlResourceParser.START_TAG);
+
+ ArrayList<VendorConfig> configs = readTagList(parser, VENDORS_TAG, VENDOR_TAG,
+ new TagReader<VendorConfig>() {
+ public VendorConfig readTag(XmlPullParser parser, String tagName)
+ throws XmlPullParserException, IOException {
+ return readVendorConfig(context, parser, tagName);
+ }
+ });
+
+ ArrayMap<String, VendorConfig> configMap = new ArrayMap<>(configs.size());
+ final int numConfigs = configs.size();
+ for (int i = 0; i < numConfigs; i++) {
+ VendorConfig config = configs.get(i);
+
+ configMap.put(config.name, config);
+ }
+
+ return configMap;
+ }
+ }
+
+ /**
+ * Read a single vendor configuration.
+ *
+ * @param parser XML parser to read from
+ * @param tagName The vendor tag
+ * @param context Calling context
+ *
+ * @return A config
+ *
+ * @throws XmlPullParserException
+ * @throws IOException
+ */
+ private static VendorConfig readVendorConfig(@NonNull final Context context,
+ @NonNull XmlPullParser parser, @NonNull String tagName) throws XmlPullParserException,
+ IOException {
+ parser.require(XmlPullParser.START_TAG, null, tagName);
+
+ String name = null;
+ String packageName = null;
+ List<String> mDNSNames = null;
+
+ while (parser.next() != XmlPullParser.END_TAG) {
+ if (parser.getEventType() != XmlPullParser.START_TAG) {
+ continue;
+ }
+
+ String subTagName = parser.getName();
+
+ switch (subTagName) {
+ case NAME_TAG:
+ name = readSimpleTag(context, parser, NAME_TAG, false);
+ break;
+ case PACKAGE_TAG:
+ packageName = readSimpleTag(context, parser, PACKAGE_TAG, true);
+ break;
+ case MDNSNAMES_TAG:
+ mDNSNames = readTagList(parser, MDNSNAMES_TAG, MDNSNAME_TAG,
+ new TagReader<String>() {
+ public String readTag(XmlPullParser parser, String tagName)
+ throws XmlPullParserException, IOException {
+ return readSimpleTag(context, parser, tagName, true);
+ }
+ }
+ );
+ break;
+ default:
+ throw new XmlPullParserException("Unexpected subtag of " + tagName + ": "
+ + subTagName);
+
+ }
+ }
+
+ if (name == null) {
+ throw new XmlPullParserException("name is required");
+ }
+
+ if (packageName == null) {
+ throw new XmlPullParserException("package is required");
+ }
+
+ if (mDNSNames == null) {
+ mDNSNames = Collections.emptyList();
+ }
+
+ // A vendor config should be immutable
+ mDNSNames = Collections.unmodifiableList(mDNSNames);
+
+ return new VendorConfig(name, packageName, mDNSNames);
+ }
+
+ @Override
+ public String toString() {
+ return name + " -> " + packageName + ", " + mDNSNames;
+ }
+
+ /**
+ * Used a a "function pointer" when reading a tag in {@link #readTagList(XmlPullParser, String,
+ * String, TagReader)}.
+ *
+ * @param <T> The type of content to read
+ */
+ private interface TagReader<T> {
+ T readTag(XmlPullParser parser, String tagName) throws XmlPullParserException, IOException;
+ }
+}
diff --git a/packages/PrintServiceRecommendationService/src/com/android/printservice/recommendation/util/MDNSUtils.java b/packages/PrintServiceRecommendationService/src/com/android/printservice/recommendation/util/MDNSUtils.java
new file mode 100644
index 0000000..0541c35
--- /dev/null
+++ b/packages/PrintServiceRecommendationService/src/com/android/printservice/recommendation/util/MDNSUtils.java
@@ -0,0 +1,98 @@
+/*
+ * (c) Copyright 2016 Mopria Alliance, Inc.
+ * (c) 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.printservice.recommendation.util;
+
+import android.annotation.NonNull;
+import android.net.nsd.NsdServiceInfo;
+
+import java.nio.charset.StandardCharsets;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Utils for dealing with mDNS attributes
+ */
+public class MDNSUtils {
+ public static final String ATTRIBUTE_TY = "ty";
+ public static final String ATTRIBUTE_PRODUCT = "product";
+ public static final String ATTRIBUTE_USB_MFG = "usb_mfg";
+ public static final String ATTRIBUTE_MFG = "mfg";
+
+ /**
+ * Check if the service has any of a set of vendor names.
+ *
+ * @param serviceInfo The service
+ * @param vendorNames The vendors
+ *
+ * @return true iff the has any of the set of vendor names
+ */
+ public static boolean isVendorPrinter(@NonNull NsdServiceInfo serviceInfo,
+ @NonNull Set<String> vendorNames) {
+ for (Map.Entry<String, byte[]> entry : serviceInfo.getAttributes().entrySet()) {
+ // keys are case insensitive
+ String key = entry.getKey().toLowerCase();
+
+ switch (key) {
+ case ATTRIBUTE_TY:
+ case ATTRIBUTE_PRODUCT:
+ case ATTRIBUTE_USB_MFG:
+ case ATTRIBUTE_MFG:
+ if (entry.getValue() != null) {
+ if (containsVendor(new String(entry.getValue(), StandardCharsets.UTF_8),
+ vendorNames)) {
+ return true;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Check if the attribute matches any of the vendor names, ignoring capitalization.
+ *
+ * @param attr The attribute
+ * @param vendorNames The vendor names
+ *
+ * @return true iff the attribute matches any of the vendor names
+ */
+ private static boolean containsVendor(@NonNull String attr, @NonNull Set<String> vendorNames) {
+ for (String name : vendorNames) {
+ if (containsString(attr.toLowerCase(), name.toLowerCase())) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Check if a string in another string.
+ *
+ * @param container The string that contains the string
+ * @param contained The string that is contained
+ *
+ * @return true if the string is contained in the other
+ */
+ private static boolean containsString(@NonNull String container, @NonNull String contained) {
+ return container.equalsIgnoreCase(contained) || container.contains(contained + " ");
+ }
+}
diff --git a/packages/PrintServiceRecommendationService/src/com/android/printservice/recommendation/util/NsdResolveQueue.java b/packages/PrintServiceRecommendationService/src/com/android/printservice/recommendation/util/NsdResolveQueue.java
new file mode 100644
index 0000000..fad50f6
--- /dev/null
+++ b/packages/PrintServiceRecommendationService/src/com/android/printservice/recommendation/util/NsdResolveQueue.java
@@ -0,0 +1,133 @@
+/*
+ * 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.printservice.recommendation.util;
+
+import android.annotation.NonNull;
+import android.net.nsd.NsdManager;
+import android.net.nsd.NsdServiceInfo;
+import com.android.internal.annotations.GuardedBy;
+
+import java.util.LinkedList;
+
+/**
+ * Nsd resolve requests for the same info cancel each other. Hence this class synchronizes the
+ * resolutions to hide this effect.
+ */
+public class NsdResolveQueue {
+ /** Lock for {@link #sInstance} */
+ private static final Object sLock = new Object();
+
+ /** Instance of this singleton */
+ @GuardedBy("sLock")
+ private static NsdResolveQueue sInstance;
+
+ /** Lock for {@link #mResolveRequests} */
+ private final Object mLock = new Object();
+
+ /** Current set of registered service info resolve attempts */
+ @GuardedBy("mLock")
+ private final LinkedList<NsdResolveRequest> mResolveRequests = new LinkedList<>();
+
+ public static NsdResolveQueue getInstance() {
+ synchronized (sLock) {
+ if (sInstance == null) {
+ sInstance = new NsdResolveQueue();
+ }
+
+ return sInstance;
+ }
+ }
+
+ /**
+ * Container for a request to resolve a serviceInfo.
+ */
+ private static class NsdResolveRequest {
+ final @NonNull NsdManager nsdManager;
+ final @NonNull NsdServiceInfo serviceInfo;
+ final @NonNull NsdManager.ResolveListener listener;
+
+ private NsdResolveRequest(@NonNull NsdManager nsdManager,
+ @NonNull NsdServiceInfo serviceInfo, @NonNull NsdManager.ResolveListener listener) {
+ this.nsdManager = nsdManager;
+ this.serviceInfo = serviceInfo;
+ this.listener = listener;
+ }
+ }
+
+ /**
+ * Resolve a serviceInfo or queue the request if there is a request currently in flight.
+ *
+ * @param nsdManager The nsd manager to use
+ * @param serviceInfo The service info to resolve
+ * @param listener The listener to call back once the info is resolved.
+ */
+ public void resolve(@NonNull NsdManager nsdManager, @NonNull NsdServiceInfo serviceInfo,
+ @NonNull NsdManager.ResolveListener listener) {
+ synchronized (mLock) {
+ mResolveRequests.addLast(new NsdResolveRequest(nsdManager, serviceInfo,
+ new ListenerWrapper(listener)));
+
+ if (mResolveRequests.size() == 1) {
+ resolveNextRequest();
+ }
+ }
+ }
+
+ /**
+ * Wrapper for a {@link NsdManager.ResolveListener}. Calls the listener and then
+ * {@link #resolveNextRequest()}.
+ */
+ private class ListenerWrapper implements NsdManager.ResolveListener {
+ private final @NonNull NsdManager.ResolveListener mListener;
+
+ private ListenerWrapper(@NonNull NsdManager.ResolveListener listener) {
+ mListener = listener;
+ }
+
+ @Override
+ public void onResolveFailed(NsdServiceInfo serviceInfo, int errorCode) {
+ mListener.onResolveFailed(serviceInfo, errorCode);
+
+ synchronized (mLock) {
+ mResolveRequests.pop();
+ resolveNextRequest();
+ }
+ }
+
+ @Override
+ public void onServiceResolved(NsdServiceInfo serviceInfo) {
+ mListener.onServiceResolved(serviceInfo);
+
+ synchronized (mLock) {
+ mResolveRequests.pop();
+ resolveNextRequest();
+ }
+ }
+ }
+
+ /**
+ * Resolve the next request if there is one.
+ */
+ private void resolveNextRequest() {
+ if (!mResolveRequests.isEmpty()) {
+ NsdResolveRequest request = mResolveRequests.getFirst();
+
+ request.nsdManager.resolveService(request.serviceInfo, request.listener);
+ }
+ }
+
+}
diff --git a/packages/PrintSpooler/res/drawable/ic_download_from_market.xml b/packages/PrintSpooler/res/drawable/ic_download_from_market.xml
new file mode 100644
index 0000000..44a5edf
--- /dev/null
+++ b/packages/PrintSpooler/res/drawable/ic_download_from_market.xml
@@ -0,0 +1,25 @@
+<?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.
+-->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="36dp"
+ android:height="36dp"
+ android:viewportWidth="48.0"
+ android:viewportHeight="48.0">
+ <path
+ android:pathData="M40,12h-8L32,8l-4,-4h-8l-4,4v4L8,12c-2.21,0 -3.98,1.79 -3.98,4L4,38c0,2.21 1.79,4 4,4h32c2.21,0 4,-1.79 4,-4L44,16c0,-2.21 -1.79,-4 -4,-4zM20,8h8v4h-8L20,8zM24,38L14,28h6v-8h8v8h6L24,38z"
+ android:fillColor="?android:attr/colorAccent"/>
+</vector>
diff --git a/packages/PrintSpooler/res/layout/print_service_recommendations_list_item.xml b/packages/PrintSpooler/res/layout/print_service_recommendations_list_item.xml
new file mode 100644
index 0000000..86ac26d
--- /dev/null
+++ b/packages/PrintSpooler/res/layout/print_service_recommendations_list_item.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.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="?android:attr/listPreferredItemHeight"
+ android:paddingStart="?android:attr/listPreferredItemPaddingStart"
+ android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
+ android:orientation="horizontal"
+ android:gravity="start|center_vertical">
+
+ <ImageView
+ android:layout_width="36dip"
+ android:layout_height="36dip"
+ android:src="@drawable/ic_download_from_market"
+ android:layout_marginRight="4dip"
+ android:layout_gravity="center_vertical"
+ android:contentDescription="@null" />
+
+ <RelativeLayout
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="16dip">
+
+ <TextView
+ android:id="@+id/title"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textAppearance="?android:attr/textAppearanceListItem"
+ android:singleLine="true"
+ android:ellipsize="end" />
+
+ <TextView
+ android:id="@+id/subtitle"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_below="@id/title"
+ android:textAppearance="?android:attr/textAppearanceListItemSecondary"
+ android:text="@string/enable_print_service" />
+
+ </RelativeLayout>
+
+</LinearLayout>
diff --git a/packages/PrintSpooler/res/values-af/strings.xml b/packages/PrintSpooler/res/values-af/strings.xml
index 0224c6c..fa5ec3f 100644
--- a/packages/PrintSpooler/res/values-af/strings.xml
+++ b/packages/PrintSpooler/res/values-af/strings.xml
@@ -72,6 +72,10 @@
<string name="recommended_services_title" msgid="3799434882937956924">"Aanbevole dienste"</string>
<string name="disabled_services_title" msgid="7313253167968363211">"Gedeaktiveerde dienste"</string>
<string name="all_services_title" msgid="5578662754874906455">"Alle dienste"</string>
+ <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+ <item quantity="other">Installeer om <xliff:g id="COUNT_1">%1$s</xliff:g> drukkers te ontdek</item>
+ <item quantity="one">Installeer om <xliff:g id="COUNT_0">%1$s</xliff:g> drukker ontdek</item>
+ </plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"Druk tans <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"Kanselleer tans <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"Drukkerfout by <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-am/strings.xml b/packages/PrintSpooler/res/values-am/strings.xml
index 98255d4..5ada8d3 100644
--- a/packages/PrintSpooler/res/values-am/strings.xml
+++ b/packages/PrintSpooler/res/values-am/strings.xml
@@ -72,6 +72,10 @@
<string name="recommended_services_title" msgid="3799434882937956924">"የሚመከሩ አገልግሎቶች"</string>
<string name="disabled_services_title" msgid="7313253167968363211">"የተሰናከሉ አገልግሎቶች"</string>
<string name="all_services_title" msgid="5578662754874906455">"ሁሉም አገልግሎቶች"</string>
+ <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+ <item quantity="one"><xliff:g id="COUNT_1">%1$s</xliff:g> አታሚዎች ለማግኘት ይጫኑ</item>
+ <item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> አታሚዎች ለማግኘት ይጫኑ</item>
+ </plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>ን በማተም ላይ"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>ን በመተው ላይ"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"የአታሚ ስህተት <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-ar/strings.xml b/packages/PrintSpooler/res/values-ar/strings.xml
index 5f0255c..1208298 100644
--- a/packages/PrintSpooler/res/values-ar/strings.xml
+++ b/packages/PrintSpooler/res/values-ar/strings.xml
@@ -76,6 +76,14 @@
<string name="recommended_services_title" msgid="3799434882937956924">"الخدمات الموصى بها"</string>
<string name="disabled_services_title" msgid="7313253167968363211">"الخدمات المعطَّلة"</string>
<string name="all_services_title" msgid="5578662754874906455">"جميع الخدمات"</string>
+ <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+ <item quantity="zero">التثبيت لاستكشاف <xliff:g id="COUNT_1">%1$s</xliff:g> طابعات</item>
+ <item quantity="two">التثبيت لاستكشاف طابعتين (<xliff:g id="COUNT_1">%1$s</xliff:g>)</item>
+ <item quantity="few">التثبيت لاستكشاف <xliff:g id="COUNT_1">%1$s</xliff:g> طابعات</item>
+ <item quantity="many">التثبيت لاستكشاف <xliff:g id="COUNT_1">%1$s</xliff:g> طابعة</item>
+ <item quantity="other">التثبيت لاستكشاف <xliff:g id="COUNT_1">%1$s</xliff:g> طابعات</item>
+ <item quantity="one">التثبيت لاستكشاف <xliff:g id="COUNT_0">%1$s</xliff:g> طابعة</item>
+ </plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"جارٍ طباعة <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"جارٍ إلغاء <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"خطا في الطابعة <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-az-rAZ/strings.xml b/packages/PrintSpooler/res/values-az-rAZ/strings.xml
index b5dfaf8..4404aad 100644
--- a/packages/PrintSpooler/res/values-az-rAZ/strings.xml
+++ b/packages/PrintSpooler/res/values-az-rAZ/strings.xml
@@ -72,6 +72,10 @@
<string name="recommended_services_title" msgid="3799434882937956924">"Tövsiyə olunan xidmətlər"</string>
<string name="disabled_services_title" msgid="7313253167968363211">"Deaktiv edilmiş xidmətlər"</string>
<string name="all_services_title" msgid="5578662754874906455">"Bütün xidmətlər"</string>
+ <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+ <item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> printeri kəşf etmək üçün quraşdırın</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%1$s</xliff:g> printeri kəşf etmək üçün quraşdırın</item>
+ </plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> çap edilir"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> ləğv edilir"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"Printer xətası <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-b+sr+Latn/strings.xml b/packages/PrintSpooler/res/values-b+sr+Latn/strings.xml
index 2ac8002..50ce1f9 100644
--- a/packages/PrintSpooler/res/values-b+sr+Latn/strings.xml
+++ b/packages/PrintSpooler/res/values-b+sr+Latn/strings.xml
@@ -73,6 +73,11 @@
<string name="recommended_services_title" msgid="3799434882937956924">"Preporučene usluge"</string>
<string name="disabled_services_title" msgid="7313253167968363211">"Onemogućene usluge"</string>
<string name="all_services_title" msgid="5578662754874906455">"Sve usluge"</string>
+ <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+ <item quantity="one">Instalirajte da biste otkrili <xliff:g id="COUNT_1">%1$s</xliff:g> štampač</item>
+ <item quantity="few">Instalirajte da biste otkrili <xliff:g id="COUNT_1">%1$s</xliff:g> štampača</item>
+ <item quantity="other">Instalirajte da biste otkrili <xliff:g id="COUNT_1">%1$s</xliff:g> štampača</item>
+ </plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"Štampa se <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"Otkazuje se <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"Greška štampača <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-be-rBY/strings.xml b/packages/PrintSpooler/res/values-be-rBY/strings.xml
index 13d573e..c264f92 100644
--- a/packages/PrintSpooler/res/values-be-rBY/strings.xml
+++ b/packages/PrintSpooler/res/values-be-rBY/strings.xml
@@ -74,6 +74,12 @@
<string name="recommended_services_title" msgid="3799434882937956924">"Рэкамендаваныя службы"</string>
<string name="disabled_services_title" msgid="7313253167968363211">"Адключаныя службы"</string>
<string name="all_services_title" msgid="5578662754874906455">"Усе службы"</string>
+ <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+ <item quantity="one">Усталюйце, каб знайсці <xliff:g id="COUNT_1">%1$s</xliff:g> прынтар</item>
+ <item quantity="few">Усталюйце, каб знайсці <xliff:g id="COUNT_1">%1$s</xliff:g> прынтары</item>
+ <item quantity="many">Усталюйце, каб знайсці <xliff:g id="COUNT_1">%1$s</xliff:g> прынтараў</item>
+ <item quantity="other">Усталюйце, каб знайсці <xliff:g id="COUNT_1">%1$s</xliff:g> прынтара</item>
+ </plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"Друк <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"Скасоўваецца <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"Памылка друку <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-bg/strings.xml b/packages/PrintSpooler/res/values-bg/strings.xml
index 73c51e9..3dd6ec5 100644
--- a/packages/PrintSpooler/res/values-bg/strings.xml
+++ b/packages/PrintSpooler/res/values-bg/strings.xml
@@ -72,6 +72,10 @@
<string name="recommended_services_title" msgid="3799434882937956924">"Препоръчителни услуги"</string>
<string name="disabled_services_title" msgid="7313253167968363211">"Деактивирани услуги"</string>
<string name="all_services_title" msgid="5578662754874906455">"Всички услуги"</string>
+ <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+ <item quantity="other">Инсталирайте, за да бъдат открити <xliff:g id="COUNT_1">%1$s</xliff:g> принтера</item>
+ <item quantity="one">Инсталирайте, за да бъде открит <xliff:g id="COUNT_0">%1$s</xliff:g> принтер</item>
+ </plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"„<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>“ се отпечатва"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"„<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>“ се анулира"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"Грешка в принтера при „<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>“"</string>
diff --git a/packages/PrintSpooler/res/values-bn-rBD/strings.xml b/packages/PrintSpooler/res/values-bn-rBD/strings.xml
index 25b4660..3789f21 100644
--- a/packages/PrintSpooler/res/values-bn-rBD/strings.xml
+++ b/packages/PrintSpooler/res/values-bn-rBD/strings.xml
@@ -72,6 +72,10 @@
<string name="recommended_services_title" msgid="3799434882937956924">"প্রস্তাবিত পরিষেবাগুলি"</string>
<string name="disabled_services_title" msgid="7313253167968363211">"অক্ষম করা পরিষেবাগুলি"</string>
<string name="all_services_title" msgid="5578662754874906455">"সমস্ত পরিষেবা"</string>
+ <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+ <item quantity="one"><xliff:g id="COUNT_1">%1$s</xliff:g>টি মুদ্রক খুঁজে পেতে ইনস্টল করুন</item>
+ <item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g>টি মুদ্রক খুঁজে পেতে ইনস্টল করুন</item>
+ </plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> প্রিন্ট করা হচ্ছে"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> বাতিল করা হচ্ছে"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> মুদ্রক ত্রুটি"</string>
diff --git a/packages/PrintSpooler/res/values-bs-rBA/strings.xml b/packages/PrintSpooler/res/values-bs-rBA/strings.xml
index 9a17707..c3c9bb33 100644
--- a/packages/PrintSpooler/res/values-bs-rBA/strings.xml
+++ b/packages/PrintSpooler/res/values-bs-rBA/strings.xml
@@ -73,6 +73,11 @@
<string name="recommended_services_title" msgid="3799434882937956924">"Preporučene usluge"</string>
<string name="disabled_services_title" msgid="7313253167968363211">"Isključene usluge"</string>
<string name="all_services_title" msgid="5578662754874906455">"Sve usluge"</string>
+ <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+ <item quantity="one"> Instaliraj da pronađeš <xliff:g id="COUNT_1">%1$s</xliff:g> štampač</item>
+ <item quantity="few"> Instaliraj da pronađeš <xliff:g id="COUNT_1">%1$s</xliff:g> štampača</item>
+ <item quantity="other"> Instaliraj da pronađeš <xliff:g id="COUNT_1">%1$s</xliff:g> štampača</item>
+ </plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"Štampa se <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"Otkazivanje <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"Greška pri štampanju <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-ca/strings.xml b/packages/PrintSpooler/res/values-ca/strings.xml
index a1df406..f65a63c 100644
--- a/packages/PrintSpooler/res/values-ca/strings.xml
+++ b/packages/PrintSpooler/res/values-ca/strings.xml
@@ -72,6 +72,10 @@
<string name="recommended_services_title" msgid="3799434882937956924">"Serveis recomanats"</string>
<string name="disabled_services_title" msgid="7313253167968363211">"Serveis desactivats"</string>
<string name="all_services_title" msgid="5578662754874906455">"Tots els serveis"</string>
+ <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+ <item quantity="other">Instal·la\'l per detectar <xliff:g id="COUNT_1">%1$s</xliff:g> impressores</item>
+ <item quantity="one">Instal·la\'l per detectar <xliff:g id="COUNT_0">%1$s</xliff:g> impressora</item>
+ </plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"S\'està imprimint <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"S\'està cancel·lant <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"Error d\'impressora <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-cs/strings.xml b/packages/PrintSpooler/res/values-cs/strings.xml
index 55fb21b..9bfa271 100644
--- a/packages/PrintSpooler/res/values-cs/strings.xml
+++ b/packages/PrintSpooler/res/values-cs/strings.xml
@@ -74,6 +74,12 @@
<string name="recommended_services_title" msgid="3799434882937956924">"Doporučené služby"</string>
<string name="disabled_services_title" msgid="7313253167968363211">"Deaktivované služby"</string>
<string name="all_services_title" msgid="5578662754874906455">"Všechny služby"</string>
+ <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+ <item quantity="few">Instalací objevíte <xliff:g id="COUNT_1">%1$s</xliff:g> tiskárny</item>
+ <item quantity="many">Instalací objevíte <xliff:g id="COUNT_1">%1$s</xliff:g> tiskárny</item>
+ <item quantity="other">Instalací objevíte <xliff:g id="COUNT_1">%1$s</xliff:g> tiskáren</item>
+ <item quantity="one">Instalací objevíte <xliff:g id="COUNT_0">%1$s</xliff:g> tiskárnu</item>
+ </plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"Tisk úlohy <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"Rušení úlohy <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"Chyba tiskárny u úlohy <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-da/strings.xml b/packages/PrintSpooler/res/values-da/strings.xml
index 49417bd..75a0b56 100644
--- a/packages/PrintSpooler/res/values-da/strings.xml
+++ b/packages/PrintSpooler/res/values-da/strings.xml
@@ -72,6 +72,10 @@
<string name="recommended_services_title" msgid="3799434882937956924">"Anbefalede tjenester"</string>
<string name="disabled_services_title" msgid="7313253167968363211">"Deaktiverede tjenester"</string>
<string name="all_services_title" msgid="5578662754874906455">"Alle tjenester"</string>
+ <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+ <item quantity="one">Installer for at finde <xliff:g id="COUNT_1">%1$s</xliff:g> printer</item>
+ <item quantity="other">Installer for at finde <xliff:g id="COUNT_1">%1$s</xliff:g> printere</item>
+ </plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> udskrives"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> annulleres"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"Udskriften <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> mislykkedes"</string>
diff --git a/packages/PrintSpooler/res/values-de/strings.xml b/packages/PrintSpooler/res/values-de/strings.xml
index cb7aeee..8c6181d 100644
--- a/packages/PrintSpooler/res/values-de/strings.xml
+++ b/packages/PrintSpooler/res/values-de/strings.xml
@@ -72,6 +72,10 @@
<string name="recommended_services_title" msgid="3799434882937956924">"Empfohlene Dienste"</string>
<string name="disabled_services_title" msgid="7313253167968363211">"Deaktivierte Dienste"</string>
<string name="all_services_title" msgid="5578662754874906455">"Alle Dienste"</string>
+ <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+ <item quantity="other">Installieren, um <xliff:g id="COUNT_1">%1$s</xliff:g> Drucker zu erkennen</item>
+ <item quantity="one">Installieren, um <xliff:g id="COUNT_0">%1$s</xliff:g> Drucker zu erkennen</item>
+ </plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> wird gedruckt..."</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> wird abgebrochen..."</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"Druckerfehler <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-el/strings.xml b/packages/PrintSpooler/res/values-el/strings.xml
index 4441ea2..31d3f83 100644
--- a/packages/PrintSpooler/res/values-el/strings.xml
+++ b/packages/PrintSpooler/res/values-el/strings.xml
@@ -72,6 +72,10 @@
<string name="recommended_services_title" msgid="3799434882937956924">"Προτεινόμενες υπηρεσίες"</string>
<string name="disabled_services_title" msgid="7313253167968363211">"Υπηρεσίες για άτομα με αναπηρία"</string>
<string name="all_services_title" msgid="5578662754874906455">"Όλες οι υπηρεσίες"</string>
+ <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+ <item quantity="other">Κάντε εγκατάσταση για να ανακαλύψετε <xliff:g id="COUNT_1">%1$s</xliff:g> εκτυπωτές</item>
+ <item quantity="one">Κάντε εγκατάσταση για να ανακαλύψετε <xliff:g id="COUNT_0">%1$s</xliff:g> εκτυπωτή</item>
+ </plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"Εκτύπωση <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"Ακύρωση <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"Σφάλμα εκτυπωτή <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-en-rAU/strings.xml b/packages/PrintSpooler/res/values-en-rAU/strings.xml
index f8b6265..5e32ae4 100644
--- a/packages/PrintSpooler/res/values-en-rAU/strings.xml
+++ b/packages/PrintSpooler/res/values-en-rAU/strings.xml
@@ -72,6 +72,10 @@
<string name="recommended_services_title" msgid="3799434882937956924">"Recommended services"</string>
<string name="disabled_services_title" msgid="7313253167968363211">"Disabled services"</string>
<string name="all_services_title" msgid="5578662754874906455">"All services"</string>
+ <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+ <item quantity="other">Install to discover <xliff:g id="COUNT_1">%1$s</xliff:g> printers</item>
+ <item quantity="one">Install to discover <xliff:g id="COUNT_0">%1$s</xliff:g> printer</item>
+ </plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"Printing <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"Cancelling <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"Printer error <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-en-rGB/strings.xml b/packages/PrintSpooler/res/values-en-rGB/strings.xml
index f8b6265..5e32ae4 100644
--- a/packages/PrintSpooler/res/values-en-rGB/strings.xml
+++ b/packages/PrintSpooler/res/values-en-rGB/strings.xml
@@ -72,6 +72,10 @@
<string name="recommended_services_title" msgid="3799434882937956924">"Recommended services"</string>
<string name="disabled_services_title" msgid="7313253167968363211">"Disabled services"</string>
<string name="all_services_title" msgid="5578662754874906455">"All services"</string>
+ <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+ <item quantity="other">Install to discover <xliff:g id="COUNT_1">%1$s</xliff:g> printers</item>
+ <item quantity="one">Install to discover <xliff:g id="COUNT_0">%1$s</xliff:g> printer</item>
+ </plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"Printing <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"Cancelling <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"Printer error <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-en-rIN/strings.xml b/packages/PrintSpooler/res/values-en-rIN/strings.xml
index f8b6265..5e32ae4 100644
--- a/packages/PrintSpooler/res/values-en-rIN/strings.xml
+++ b/packages/PrintSpooler/res/values-en-rIN/strings.xml
@@ -72,6 +72,10 @@
<string name="recommended_services_title" msgid="3799434882937956924">"Recommended services"</string>
<string name="disabled_services_title" msgid="7313253167968363211">"Disabled services"</string>
<string name="all_services_title" msgid="5578662754874906455">"All services"</string>
+ <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+ <item quantity="other">Install to discover <xliff:g id="COUNT_1">%1$s</xliff:g> printers</item>
+ <item quantity="one">Install to discover <xliff:g id="COUNT_0">%1$s</xliff:g> printer</item>
+ </plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"Printing <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"Cancelling <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"Printer error <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-es-rUS/strings.xml b/packages/PrintSpooler/res/values-es-rUS/strings.xml
index 8d55597..a6a9f07 100644
--- a/packages/PrintSpooler/res/values-es-rUS/strings.xml
+++ b/packages/PrintSpooler/res/values-es-rUS/strings.xml
@@ -72,6 +72,10 @@
<string name="recommended_services_title" msgid="3799434882937956924">"Servicios recomendados"</string>
<string name="disabled_services_title" msgid="7313253167968363211">"Servicios inhabilitados"</string>
<string name="all_services_title" msgid="5578662754874906455">"Todos los servicios"</string>
+ <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+ <item quantity="other">Instala para ver <xliff:g id="COUNT_1">%1$s</xliff:g> impresoras</item>
+ <item quantity="one">Instala para ver <xliff:g id="COUNT_0">%1$s</xliff:g> impresora</item>
+ </plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"Imprimiendo <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"Cancelando <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"Error de impresora <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-es/strings.xml b/packages/PrintSpooler/res/values-es/strings.xml
index 7d08a0e..4f6731d 100644
--- a/packages/PrintSpooler/res/values-es/strings.xml
+++ b/packages/PrintSpooler/res/values-es/strings.xml
@@ -72,6 +72,10 @@
<string name="recommended_services_title" msgid="3799434882937956924">"Servicios recomendados"</string>
<string name="disabled_services_title" msgid="7313253167968363211">"Servicios inhabilitados"</string>
<string name="all_services_title" msgid="5578662754874906455">"Todos los servicios"</string>
+ <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+ <item quantity="other">Instalar para descubrir <xliff:g id="COUNT_1">%1$s</xliff:g> impresoras</item>
+ <item quantity="one">Instalar para descubrir <xliff:g id="COUNT_0">%1$s</xliff:g> impresora</item>
+ </plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"Imprimiendo <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"Cancelando <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"Error de impresora <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-et-rEE/strings.xml b/packages/PrintSpooler/res/values-et-rEE/strings.xml
index 09da3e0..3d0516c 100644
--- a/packages/PrintSpooler/res/values-et-rEE/strings.xml
+++ b/packages/PrintSpooler/res/values-et-rEE/strings.xml
@@ -72,6 +72,10 @@
<string name="recommended_services_title" msgid="3799434882937956924">"Soovitatud teenused"</string>
<string name="disabled_services_title" msgid="7313253167968363211">"Keelatud teenused"</string>
<string name="all_services_title" msgid="5578662754874906455">"Kõik teenused"</string>
+ <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+ <item quantity="other">Installige <xliff:g id="COUNT_1">%1$s</xliff:g> printeri avastamiseks</item>
+ <item quantity="one">Installige <xliff:g id="COUNT_0">%1$s</xliff:g> printeri avastamiseks</item>
+ </plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"Prinditöö <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> printimine"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"Prinditöö <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> tühistamine"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"Printeri viga: <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-eu-rES/strings.xml b/packages/PrintSpooler/res/values-eu-rES/strings.xml
index 6b760b4..c56692f 100644
--- a/packages/PrintSpooler/res/values-eu-rES/strings.xml
+++ b/packages/PrintSpooler/res/values-eu-rES/strings.xml
@@ -72,6 +72,10 @@
<string name="recommended_services_title" msgid="3799434882937956924">"Gomendatutako zerbitzuak"</string>
<string name="disabled_services_title" msgid="7313253167968363211">"Desgaitutako zerbitzuak"</string>
<string name="all_services_title" msgid="5578662754874906455">"Zerbitzu guztiak"</string>
+ <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+ <item quantity="other">Instalatu <xliff:g id="COUNT_1">%1$s</xliff:g> inprimagailu aurkitzeko</item>
+ <item quantity="one">Instalatu <xliff:g id="COUNT_0">%1$s</xliff:g> inprimagailu aurkitzeko</item>
+ </plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> inprimatzen"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> bertan behera uzten"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"Errorea <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> inprimatzean"</string>
diff --git a/packages/PrintSpooler/res/values-fa/strings.xml b/packages/PrintSpooler/res/values-fa/strings.xml
index fa105d5..8a6c0dd 100644
--- a/packages/PrintSpooler/res/values-fa/strings.xml
+++ b/packages/PrintSpooler/res/values-fa/strings.xml
@@ -72,6 +72,10 @@
<string name="recommended_services_title" msgid="3799434882937956924">"خدمات توصیهشده"</string>
<string name="disabled_services_title" msgid="7313253167968363211">"خدمات غیرفعال"</string>
<string name="all_services_title" msgid="5578662754874906455">"همه خدمات"</string>
+ <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+ <item quantity="one">نصب کنید تا <xliff:g id="COUNT_1">%1$s</xliff:g> چاپگر را پیدا کنید</item>
+ <item quantity="other">نصب کنید تا <xliff:g id="COUNT_1">%1$s</xliff:g> چاپگر را پیدا کنید</item>
+ </plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"در حال چاپ <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"در حال لغو <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"خطای چاپگر <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-fi/strings.xml b/packages/PrintSpooler/res/values-fi/strings.xml
index cf051f8..3d6897d 100644
--- a/packages/PrintSpooler/res/values-fi/strings.xml
+++ b/packages/PrintSpooler/res/values-fi/strings.xml
@@ -72,6 +72,10 @@
<string name="recommended_services_title" msgid="3799434882937956924">"Suositellut palvelut"</string>
<string name="disabled_services_title" msgid="7313253167968363211">"Käytöstä poistetut palvelut"</string>
<string name="all_services_title" msgid="5578662754874906455">"Kaikki palvelut"</string>
+ <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+ <item quantity="other">Asentamalla voit löytää <xliff:g id="COUNT_1">%1$s</xliff:g> tulostinta.</item>
+ <item quantity="one">Asentamalla voit löytää <xliff:g id="COUNT_0">%1$s</xliff:g> tulostimen.</item>
+ </plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"Tulostetaan <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"Peruutetaan työ <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"Tulostinvirhe työlle <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-fr-rCA/strings.xml b/packages/PrintSpooler/res/values-fr-rCA/strings.xml
index 11d2875..6c9539a 100644
--- a/packages/PrintSpooler/res/values-fr-rCA/strings.xml
+++ b/packages/PrintSpooler/res/values-fr-rCA/strings.xml
@@ -72,6 +72,10 @@
<string name="recommended_services_title" msgid="3799434882937956924">"Services recommandés"</string>
<string name="disabled_services_title" msgid="7313253167968363211">"Services désactivés"</string>
<string name="all_services_title" msgid="5578662754874906455">"Tous les services"</string>
+ <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+ <item quantity="one">Installer pour détecter <xliff:g id="COUNT_1">%1$s</xliff:g> imprimante</item>
+ <item quantity="other">Installer pour détecter <xliff:g id="COUNT_1">%1$s</xliff:g> imprimantes</item>
+ </plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"Impression de <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> en cours…"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"Annulation de « <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> »…"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"Erreur impression : « <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> »"</string>
diff --git a/packages/PrintSpooler/res/values-fr/strings.xml b/packages/PrintSpooler/res/values-fr/strings.xml
index 6b89281..64add68 100644
--- a/packages/PrintSpooler/res/values-fr/strings.xml
+++ b/packages/PrintSpooler/res/values-fr/strings.xml
@@ -72,6 +72,10 @@
<string name="recommended_services_title" msgid="3799434882937956924">"Services recommandés"</string>
<string name="disabled_services_title" msgid="7313253167968363211">"Services désactivés"</string>
<string name="all_services_title" msgid="5578662754874906455">"Tous les services"</string>
+ <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+ <item quantity="one">Installer pour détecter <xliff:g id="COUNT_1">%1$s</xliff:g> imprimante</item>
+ <item quantity="other">Installer pour détecter <xliff:g id="COUNT_1">%1$s</xliff:g> imprimantes</item>
+ </plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"Impression de \"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>\" en cours…"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"Annulation de \"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>\" en cours…"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"Erreur impression pour \"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>\""</string>
diff --git a/packages/PrintSpooler/res/values-gl-rES/strings.xml b/packages/PrintSpooler/res/values-gl-rES/strings.xml
index 7ddc9f8..099159d 100644
--- a/packages/PrintSpooler/res/values-gl-rES/strings.xml
+++ b/packages/PrintSpooler/res/values-gl-rES/strings.xml
@@ -72,6 +72,10 @@
<string name="recommended_services_title" msgid="3799434882937956924">"Servizos recomendados"</string>
<string name="disabled_services_title" msgid="7313253167968363211">"Servizos desactivados"</string>
<string name="all_services_title" msgid="5578662754874906455">"Todos os servizos"</string>
+ <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+ <item quantity="other">Instala o servizo para atopar <xliff:g id="COUNT_1">%1$s</xliff:g> impresoras</item>
+ <item quantity="one">Instala o servizo para atopar <xliff:g id="COUNT_0">%1$s</xliff:g> impresora</item>
+ </plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"Imprimindo <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"Cancelando <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"Erro da impresora <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-gu-rIN/strings.xml b/packages/PrintSpooler/res/values-gu-rIN/strings.xml
index 6a7e0df..b42fdab 100644
--- a/packages/PrintSpooler/res/values-gu-rIN/strings.xml
+++ b/packages/PrintSpooler/res/values-gu-rIN/strings.xml
@@ -72,6 +72,10 @@
<string name="recommended_services_title" msgid="3799434882937956924">"ભલામણ કરેલી સેવાઓ"</string>
<string name="disabled_services_title" msgid="7313253167968363211">"અક્ષમ કરેલી સેવાઓ"</string>
<string name="all_services_title" msgid="5578662754874906455">"બધી સેવાઓ"</string>
+ <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+ <item quantity="one"><xliff:g id="COUNT_1">%1$s</xliff:g> પ્રિન્ટરની શોધ કરવા માટે ઇન્સ્ટૉલ કરો</item>
+ <item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> પ્રિન્ટરની શોધ કરવા માટે ઇન્સ્ટૉલ કરો</item>
+ </plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> છાપી રહ્યાં છે"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> ને રદ કરી રહ્યું છે"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"પ્રિન્ટર ભૂલ <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-hi/strings.xml b/packages/PrintSpooler/res/values-hi/strings.xml
index 377dc62..507754a0 100644
--- a/packages/PrintSpooler/res/values-hi/strings.xml
+++ b/packages/PrintSpooler/res/values-hi/strings.xml
@@ -72,6 +72,10 @@
<string name="recommended_services_title" msgid="3799434882937956924">"सुझाई गई सेवाएं"</string>
<string name="disabled_services_title" msgid="7313253167968363211">"अक्षम सेवाएं"</string>
<string name="all_services_title" msgid="5578662754874906455">"सभी सेवाएं"</string>
+ <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+ <item quantity="one"><xliff:g id="COUNT_1">%1$s</xliff:g> प्रिंटर खोजने के लिए इंस्टॉल करें</item>
+ <item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> प्रिंटर खोजने के लिए इंस्टॉल करें</item>
+ </plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> प्रिंट हो रहा है"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> रद्द हो रहा है"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"प्रिंटर त्रुटि <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-hr/strings.xml b/packages/PrintSpooler/res/values-hr/strings.xml
index 8550be4..92c97ea 100644
--- a/packages/PrintSpooler/res/values-hr/strings.xml
+++ b/packages/PrintSpooler/res/values-hr/strings.xml
@@ -73,6 +73,11 @@
<string name="recommended_services_title" msgid="3799434882937956924">"Preporučene usluge"</string>
<string name="disabled_services_title" msgid="7313253167968363211">"Onemogućene usluge"</string>
<string name="all_services_title" msgid="5578662754874906455">"Sve usluge"</string>
+ <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+ <item quantity="one">Instalirajte da biste pronašli <xliff:g id="COUNT_1">%1$s</xliff:g> pisač</item>
+ <item quantity="few">Instalirajte da biste pronašli <xliff:g id="COUNT_1">%1$s</xliff:g> pisača</item>
+ <item quantity="other">Instalirajte da biste pronašli <xliff:g id="COUNT_1">%1$s</xliff:g> pisača</item>
+ </plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"Ispisivanje <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"Otkazivanje zadatka <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"Pogreška pisača <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-hu/strings.xml b/packages/PrintSpooler/res/values-hu/strings.xml
index 20789a3..a2e53db 100644
--- a/packages/PrintSpooler/res/values-hu/strings.xml
+++ b/packages/PrintSpooler/res/values-hu/strings.xml
@@ -72,6 +72,10 @@
<string name="recommended_services_title" msgid="3799434882937956924">"Javasolt szolgáltatások"</string>
<string name="disabled_services_title" msgid="7313253167968363211">"Letiltott szolgáltatások"</string>
<string name="all_services_title" msgid="5578662754874906455">"Minden szolgáltatás"</string>
+ <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+ <item quantity="other">Telepítés <xliff:g id="COUNT_1">%1$s</xliff:g> nyomtató felfedezéséhez</item>
+ <item quantity="one">Telepítés <xliff:g id="COUNT_0">%1$s</xliff:g> nyomtató felfedezéséhez</item>
+ </plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"A(z) <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> nyomtatása"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"A(z) <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> törlése"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"Nyomtatási hiba: <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-hy-rAM/strings.xml b/packages/PrintSpooler/res/values-hy-rAM/strings.xml
index 8950338..e26c244 100644
--- a/packages/PrintSpooler/res/values-hy-rAM/strings.xml
+++ b/packages/PrintSpooler/res/values-hy-rAM/strings.xml
@@ -72,6 +72,10 @@
<string name="recommended_services_title" msgid="3799434882937956924">"Խորհուրդ տրվող ծառայությունները"</string>
<string name="disabled_services_title" msgid="7313253167968363211">"Կասեցված ծառայությունները"</string>
<string name="all_services_title" msgid="5578662754874906455">"Բոլոր ծառայությունները"</string>
+ <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+ <item quantity="one">Տեղադրեք՝ <xliff:g id="COUNT_1">%1$s</xliff:g> տպիչ հայտնաբերելու համար</item>
+ <item quantity="other">Տեղադրեք՝ <xliff:g id="COUNT_1">%1$s</xliff:g> տպիչ հայտնաբերելու համար</item>
+ </plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"Տպվում է՝ <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>-ը չեղարկվում է"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"Տպիչի սխալ <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-in/strings.xml b/packages/PrintSpooler/res/values-in/strings.xml
index 9b72250..4ec0644 100644
--- a/packages/PrintSpooler/res/values-in/strings.xml
+++ b/packages/PrintSpooler/res/values-in/strings.xml
@@ -72,6 +72,10 @@
<string name="recommended_services_title" msgid="3799434882937956924">"Layanan yang disarankan"</string>
<string name="disabled_services_title" msgid="7313253167968363211">"Layanan dinonaktifkan"</string>
<string name="all_services_title" msgid="5578662754874906455">"Semua layanan"</string>
+ <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+ <item quantity="other">Pasang untuk menemukan <xliff:g id="COUNT_1">%1$s</xliff:g> printer</item>
+ <item quantity="one">Pasang untuk menemukan <xliff:g id="COUNT_0">%1$s</xliff:g> printer</item>
+ </plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"Mencetak <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"Membatalkan <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"Ada kesalahan printer <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-is-rIS/strings.xml b/packages/PrintSpooler/res/values-is-rIS/strings.xml
index 37abb5a..e05f07f 100644
--- a/packages/PrintSpooler/res/values-is-rIS/strings.xml
+++ b/packages/PrintSpooler/res/values-is-rIS/strings.xml
@@ -72,6 +72,10 @@
<string name="recommended_services_title" msgid="3799434882937956924">"Þjónusta sem mælt er með"</string>
<string name="disabled_services_title" msgid="7313253167968363211">"Þjónusta við fatlaða"</string>
<string name="all_services_title" msgid="5578662754874906455">"Öll þjónusta"</string>
+ <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+ <item quantity="one">Settu upp til að finna <xliff:g id="COUNT_1">%1$s</xliff:g> prentara</item>
+ <item quantity="other">Settu upp til að finna <xliff:g id="COUNT_1">%1$s</xliff:g> prentara</item>
+ </plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"Prentar <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"Hættir við <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"Prentaravilla <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-it/strings.xml b/packages/PrintSpooler/res/values-it/strings.xml
index dd4a8cb..39a0a61 100644
--- a/packages/PrintSpooler/res/values-it/strings.xml
+++ b/packages/PrintSpooler/res/values-it/strings.xml
@@ -72,6 +72,10 @@
<string name="recommended_services_title" msgid="3799434882937956924">"Servizi consigliati"</string>
<string name="disabled_services_title" msgid="7313253167968363211">"Servizi disattivati"</string>
<string name="all_services_title" msgid="5578662754874906455">"Tutti i servizi"</string>
+ <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+ <item quantity="other">Installa per rilevare <xliff:g id="COUNT_1">%1$s</xliff:g> stampanti</item>
+ <item quantity="one">Installa per rilevare <xliff:g id="COUNT_0">%1$s</xliff:g> stampante</item>
+ </plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"Stampa di <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"Annullamento di <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"Errore della stampante: <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-iw/strings.xml b/packages/PrintSpooler/res/values-iw/strings.xml
index 1d813bb..9aa4104 100644
--- a/packages/PrintSpooler/res/values-iw/strings.xml
+++ b/packages/PrintSpooler/res/values-iw/strings.xml
@@ -74,6 +74,12 @@
<string name="recommended_services_title" msgid="3799434882937956924">"שירותים מומלצים"</string>
<string name="disabled_services_title" msgid="7313253167968363211">"שירותים מושבתים"</string>
<string name="all_services_title" msgid="5578662754874906455">"כל השירותים"</string>
+ <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+ <item quantity="two">התקן כדי לגלות <xliff:g id="COUNT_1">%1$s</xliff:g> מדפסות</item>
+ <item quantity="many">התקן כדי לגלות <xliff:g id="COUNT_1">%1$s</xliff:g> מדפסות</item>
+ <item quantity="other">התקן כדי לגלות <xliff:g id="COUNT_1">%1$s</xliff:g> מדפסות</item>
+ <item quantity="one">התקן כדי לגלות מדפסת <xliff:g id="COUNT_0">%1$s</xliff:g></item>
+ </plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"מדפיס את <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"מבטל את <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"שגיאת מדפסת ב-<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-ja/strings.xml b/packages/PrintSpooler/res/values-ja/strings.xml
index 946052a..f97efc1 100644
--- a/packages/PrintSpooler/res/values-ja/strings.xml
+++ b/packages/PrintSpooler/res/values-ja/strings.xml
@@ -72,6 +72,10 @@
<string name="recommended_services_title" msgid="3799434882937956924">"推奨されているサービス"</string>
<string name="disabled_services_title" msgid="7313253167968363211">"無効になっているサービス"</string>
<string name="all_services_title" msgid="5578662754874906455">"すべてのサービス"</string>
+ <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+ <item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> 台のプリンタを検索するにはインストールします</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%1$s</xliff:g> 台のプリンタを検索するにはインストールします</item>
+ </plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>を印刷しています"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>をキャンセルしています"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"プリンタエラー: <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-ka-rGE/strings.xml b/packages/PrintSpooler/res/values-ka-rGE/strings.xml
index 94152b1..9cb8b39 100644
--- a/packages/PrintSpooler/res/values-ka-rGE/strings.xml
+++ b/packages/PrintSpooler/res/values-ka-rGE/strings.xml
@@ -72,6 +72,10 @@
<string name="recommended_services_title" msgid="3799434882937956924">"რეკომენდებული სერვისები"</string>
<string name="disabled_services_title" msgid="7313253167968363211">"გათიშული სერვისები"</string>
<string name="all_services_title" msgid="5578662754874906455">"ყველა სერვისი"</string>
+ <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+ <item quantity="other">დააინსტალირეთ <xliff:g id="COUNT_1">%1$s</xliff:g> პრინტერის აღმოსაჩენად</item>
+ <item quantity="one">დააინსტალირეთ <xliff:g id="COUNT_0">%1$s</xliff:g> პრინტერის აღმოსაჩენად</item>
+ </plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"იბეჭდება <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"მიმდინარეობს <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>-ის გაუქმება"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"ბეჭდვის შეცდომა <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-kk-rKZ/strings.xml b/packages/PrintSpooler/res/values-kk-rKZ/strings.xml
index 2bc5ab6..37b2cd3 100644
--- a/packages/PrintSpooler/res/values-kk-rKZ/strings.xml
+++ b/packages/PrintSpooler/res/values-kk-rKZ/strings.xml
@@ -72,6 +72,10 @@
<string name="recommended_services_title" msgid="3799434882937956924">"Ұсынылған қызметтер"</string>
<string name="disabled_services_title" msgid="7313253167968363211">"Өшірілген қызметтер"</string>
<string name="all_services_title" msgid="5578662754874906455">"Барлық қызметтер"</string>
+ <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+ <item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> принтерді табу үшін орнатыңыз</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%1$s</xliff:g> принтерді табу үшін орнатыңыз</item>
+ </plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> басып шығарылуда"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> жұмысын тоқтатуда"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> принтер қателігі"</string>
@@ -99,6 +103,6 @@
<string name="print_error_default_message" msgid="8602678405502922346">"Кешіріңіз, бұл нәтиже бермеді. Әрекетті қайталаңыз."</string>
<string name="print_error_retry" msgid="1426421728784259538">"Қайталау"</string>
<string name="print_error_printer_unavailable" msgid="8985614415253203381">"Бұл принтер дәл қазір қол жетімді емес."</string>
- <string name="print_cannot_load_page" msgid="6179560924492912009">"Алдын ала қарауды көрсету мүмкін емес"</string>
+ <string name="print_cannot_load_page" msgid="6179560924492912009">"Бетті алдын ала қарау мүмкін емес"</string>
<string name="print_preparing_preview" msgid="3939930735671364712">"Алдын ала қарау дайындалуда…"</string>
</resources>
diff --git a/packages/PrintSpooler/res/values-km-rKH/strings.xml b/packages/PrintSpooler/res/values-km-rKH/strings.xml
index 330edf5..12d296d 100644
--- a/packages/PrintSpooler/res/values-km-rKH/strings.xml
+++ b/packages/PrintSpooler/res/values-km-rKH/strings.xml
@@ -72,6 +72,10 @@
<string name="recommended_services_title" msgid="3799434882937956924">"សេវាកម្មដែលបានណែនាំ"</string>
<string name="disabled_services_title" msgid="7313253167968363211">"សេវាកម្មដែលបិទដំណើរការ"</string>
<string name="all_services_title" msgid="5578662754874906455">"សេវាកម្មទាំងអស់"</string>
+ <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+ <item quantity="other">ដំឡើងដើម្បីរកមើលម៉ាស៊ីនបោះពុម្ព <xliff:g id="COUNT_1">%1$s</xliff:g></item>
+ <item quantity="one">ដំឡើងដើម្បីរកមើលម៉ាស៊ីនបោះពុម្ព <xliff:g id="COUNT_0">%1$s</xliff:g></item>
+ </plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"កំពុងបោះពុម្ព <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"ការបោះបង់ <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"កំហុសម៉ាស៊ីនបោះពុម្ព <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-kn-rIN/strings.xml b/packages/PrintSpooler/res/values-kn-rIN/strings.xml
index f1cef86..8b1acdd 100644
--- a/packages/PrintSpooler/res/values-kn-rIN/strings.xml
+++ b/packages/PrintSpooler/res/values-kn-rIN/strings.xml
@@ -72,6 +72,10 @@
<string name="recommended_services_title" msgid="3799434882937956924">"ಶಿಫಾರಸು ಮಾಡಲಾದ ಸೇವೆಗಳು"</string>
<string name="disabled_services_title" msgid="7313253167968363211">"ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲಾದ ಸೇವೆಗಳು"</string>
<string name="all_services_title" msgid="5578662754874906455">"ಎಲ್ಲ ಸೇವೆಗಳು"</string>
+ <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+ <item quantity="one"><xliff:g id="COUNT_1">%1$s</xliff:g> ಪ್ರಿಂಟರ್ಗಳನ್ನು ಶೋಧಿಸಲು ಸ್ಥಾಪಿಸಿ</item>
+ <item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> ಪ್ರಿಂಟರ್ಗಳನ್ನು ಶೋಧಿಸಲು ಸ್ಥಾಪಿಸಿ</item>
+ </plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> ಮುದ್ರಿಸಲಾಗುತ್ತಿದೆ"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> ರದ್ದು ಮಾಡಲಾಗುತ್ತಿದೆ"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"ಮುದ್ರಕ ದೋಷ <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-ko/strings.xml b/packages/PrintSpooler/res/values-ko/strings.xml
index d3cc967..e6ca240 100644
--- a/packages/PrintSpooler/res/values-ko/strings.xml
+++ b/packages/PrintSpooler/res/values-ko/strings.xml
@@ -72,6 +72,10 @@
<string name="recommended_services_title" msgid="3799434882937956924">"권장 서비스"</string>
<string name="disabled_services_title" msgid="7313253167968363211">"사용 중지된 서비스"</string>
<string name="all_services_title" msgid="5578662754874906455">"모든 서비스"</string>
+ <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+ <item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g>개 프린터를 표시하려면 설치하세요.</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%1$s</xliff:g>개 프린터를 표시하려면 설치하세요.</item>
+ </plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> 인쇄 중"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> 취소 중"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"프린터 오류: <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-ky-rKG/strings.xml b/packages/PrintSpooler/res/values-ky-rKG/strings.xml
index d84e5d8..ae0b05e 100644
--- a/packages/PrintSpooler/res/values-ky-rKG/strings.xml
+++ b/packages/PrintSpooler/res/values-ky-rKG/strings.xml
@@ -72,6 +72,10 @@
<string name="recommended_services_title" msgid="3799434882937956924">"Сунушталган кызматтар"</string>
<string name="disabled_services_title" msgid="7313253167968363211">"Өчүрүлгөн кызматтар"</string>
<string name="all_services_title" msgid="5578662754874906455">"Бардык кызматтар"</string>
+ <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+ <item quantity="other">Орнотсоңуз <xliff:g id="COUNT_1">%1$s</xliff:g> принтер таап аласыз</item>
+ <item quantity="one">Орнотсоңуз <xliff:g id="COUNT_0">%1$s</xliff:g> принтер таап аласыз</item>
+ </plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> басылууда"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> токтотулууда"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"Принтерде ката кетти: <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-lo-rLA/strings.xml b/packages/PrintSpooler/res/values-lo-rLA/strings.xml
index 6a69053..2392e4a 100644
--- a/packages/PrintSpooler/res/values-lo-rLA/strings.xml
+++ b/packages/PrintSpooler/res/values-lo-rLA/strings.xml
@@ -72,6 +72,10 @@
<string name="recommended_services_title" msgid="3799434882937956924">"ບໍລິການທີ່ແນະນຳ"</string>
<string name="disabled_services_title" msgid="7313253167968363211">"ບໍລິການທີ່ຖືກປິດການນຳໃຊ້"</string>
<string name="all_services_title" msgid="5578662754874906455">"ບໍລິການທັງໝົດ"</string>
+ <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+ <item quantity="other">ຕິດຕັ້ງເພື່ອຄົ້ນພົບເຄື່ອງພິມ <xliff:g id="COUNT_1">%1$s</xliff:g> ເຄື່ອງ</item>
+ <item quantity="one">ຕິດຕັ້ງເພື່ອຄົ້ນພົບເຄື່ອງພິມ <xliff:g id="COUNT_0">%1$s</xliff:g> ເຄື່ອງ</item>
+ </plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"ກຳລັງພິມ <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"ກຳລັງຍົກເລີກ <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"ເຄື່ອງພິມເກີດຂໍ້ຜິດພາດ <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-lt/strings.xml b/packages/PrintSpooler/res/values-lt/strings.xml
index ddcaba7..65ccc2b 100644
--- a/packages/PrintSpooler/res/values-lt/strings.xml
+++ b/packages/PrintSpooler/res/values-lt/strings.xml
@@ -74,6 +74,12 @@
<string name="recommended_services_title" msgid="3799434882937956924">"Rekomenduojamos paslaugos"</string>
<string name="disabled_services_title" msgid="7313253167968363211">"Išjungtos paslaugos"</string>
<string name="all_services_title" msgid="5578662754874906455">"Visos paslaugos"</string>
+ <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+ <item quantity="one">Įdiekite, kad būtų rastas <xliff:g id="COUNT_1">%1$s</xliff:g> spausdintuvas</item>
+ <item quantity="few">Įdiekite, kad būtų rasti <xliff:g id="COUNT_1">%1$s</xliff:g> spausdintuvai</item>
+ <item quantity="many">Įdiekite, kad būtų rasta <xliff:g id="COUNT_1">%1$s</xliff:g> spausdintuvo</item>
+ <item quantity="other">Įdiekite, kad būtų rasta <xliff:g id="COUNT_1">%1$s</xliff:g> spausdintuvų</item>
+ </plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"Spausdinama: <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"Atšaukiama: <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"Spausdintuvo klaida: <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-lv/strings.xml b/packages/PrintSpooler/res/values-lv/strings.xml
index 50ba32d..1bcfe78 100644
--- a/packages/PrintSpooler/res/values-lv/strings.xml
+++ b/packages/PrintSpooler/res/values-lv/strings.xml
@@ -73,6 +73,11 @@
<string name="recommended_services_title" msgid="3799434882937956924">"Ieteiktie pakalpojumi"</string>
<string name="disabled_services_title" msgid="7313253167968363211">"Atspējotie pakalpojumi"</string>
<string name="all_services_title" msgid="5578662754874906455">"Visi pakalpojumi"</string>
+ <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+ <item quantity="zero">Instalējiet, lai atklātu <xliff:g id="COUNT_1">%1$s</xliff:g> printerus</item>
+ <item quantity="one">Instalējiet, lai atklātu <xliff:g id="COUNT_1">%1$s</xliff:g> printeri</item>
+ <item quantity="other">Instalējiet, lai atklātu <xliff:g id="COUNT_1">%1$s</xliff:g> printerus</item>
+ </plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"Notiek darba <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> drukāšana…"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"Pārtrauc drukas darbu <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>…"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"Printera kļūda ar darbu <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-mk-rMK/strings.xml b/packages/PrintSpooler/res/values-mk-rMK/strings.xml
index a189042..d29566bc 100644
--- a/packages/PrintSpooler/res/values-mk-rMK/strings.xml
+++ b/packages/PrintSpooler/res/values-mk-rMK/strings.xml
@@ -72,6 +72,10 @@
<string name="recommended_services_title" msgid="3799434882937956924">"Препорачани услуги"</string>
<string name="disabled_services_title" msgid="7313253167968363211">"Оневозможени услуги"</string>
<string name="all_services_title" msgid="5578662754874906455">"Сите услуги"</string>
+ <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+ <item quantity="one">Инсталирајте за да пронајдете <xliff:g id="COUNT_1">%1$s</xliff:g> печатач</item>
+ <item quantity="other">Инсталирајте за да пронајдете <xliff:g id="COUNT_1">%1$s</xliff:g> печатачи</item>
+ </plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> се печати"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> се откажува"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"Грешка при печатење <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-ml-rIN/strings.xml b/packages/PrintSpooler/res/values-ml-rIN/strings.xml
index 5625632..16d654c 100644
--- a/packages/PrintSpooler/res/values-ml-rIN/strings.xml
+++ b/packages/PrintSpooler/res/values-ml-rIN/strings.xml
@@ -72,6 +72,10 @@
<string name="recommended_services_title" msgid="3799434882937956924">"ശുപാർശ ചെയ്യപ്പെടുന്ന സേവനങ്ങൾ"</string>
<string name="disabled_services_title" msgid="7313253167968363211">"പ്രവർത്തനരഹിതമാക്കിയ സേവനങ്ങൾ"</string>
<string name="all_services_title" msgid="5578662754874906455">"എല്ലാ സേവനങ്ങളും"</string>
+ <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+ <item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> പ്രിന്ററുകൾ കണ്ടെത്തുന്നതിന് ഇൻസ്റ്റാൾ ചെയ്യുക</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%1$s</xliff:g> പ്രിന്റർ കണ്ടെത്തുന്നതിന് ഇൻസ്റ്റാൾ ചെയ്യുക</item>
+ </plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> പ്രിന്റുചെയ്യുന്നു"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> റദ്ദാക്കുന്നു"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"പ്രിന്റർ പിശക് <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-mn-rMN/strings.xml b/packages/PrintSpooler/res/values-mn-rMN/strings.xml
index 7797944..ded0665 100644
--- a/packages/PrintSpooler/res/values-mn-rMN/strings.xml
+++ b/packages/PrintSpooler/res/values-mn-rMN/strings.xml
@@ -72,6 +72,10 @@
<string name="recommended_services_title" msgid="3799434882937956924">"Санал болгосон үйлчилгээ"</string>
<string name="disabled_services_title" msgid="7313253167968363211">"Идэвхгүй болгосон үйлчилгээ"</string>
<string name="all_services_title" msgid="5578662754874906455">"Бүх үйлчилгээ"</string>
+ <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+ <item quantity="other"> <xliff:g id="COUNT_1">%1$s</xliff:g> хэвлэгч олохын тулд суулгах</item>
+ <item quantity="one"> <xliff:g id="COUNT_0">%1$s</xliff:g> хэвлэгч олохын тулд суулгах</item>
+ </plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"Хэвлэж байна <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"Цуцлаж байна <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"Принтерийн алдаа <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-mr-rIN/strings.xml b/packages/PrintSpooler/res/values-mr-rIN/strings.xml
index ee09db2..5436635 100644
--- a/packages/PrintSpooler/res/values-mr-rIN/strings.xml
+++ b/packages/PrintSpooler/res/values-mr-rIN/strings.xml
@@ -72,6 +72,10 @@
<string name="recommended_services_title" msgid="3799434882937956924">"शिफारस केलेल्या सेवा"</string>
<string name="disabled_services_title" msgid="7313253167968363211">"अक्षम केलल्या सेवा"</string>
<string name="all_services_title" msgid="5578662754874906455">"सर्व सेवा"</string>
+ <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+ <item quantity="one"><xliff:g id="COUNT_1">%1$s</xliff:g> प्रिंटर शोधण्यासाठी स्थापित करा</item>
+ <item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> प्रिंटर शोधण्यासाठी स्थापित करा</item>
+ </plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> मुद्रण करीत आहे"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> रद्द करीत आहे"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"प्रिंटर त्रुटी <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-ms-rMY/strings.xml b/packages/PrintSpooler/res/values-ms-rMY/strings.xml
index 4042c71..8af5232 100644
--- a/packages/PrintSpooler/res/values-ms-rMY/strings.xml
+++ b/packages/PrintSpooler/res/values-ms-rMY/strings.xml
@@ -72,6 +72,10 @@
<string name="recommended_services_title" msgid="3799434882937956924">"Perkhidmatan yang disyorkan"</string>
<string name="disabled_services_title" msgid="7313253167968363211">"Perkhidmatan yang dilumpuhkan"</string>
<string name="all_services_title" msgid="5578662754874906455">"Semua perkhidmatan"</string>
+ <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+ <item quantity="other">Pasang untuk menemui <xliff:g id="COUNT_1">%1$s</xliff:g> pencetak</item>
+ <item quantity="one">Pasang untuk menemui <xliff:g id="COUNT_0">%1$s</xliff:g> pencetak</item>
+ </plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"Mencetak <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"Membatalkan <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"Ralat pencetak <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-my-rMM/strings.xml b/packages/PrintSpooler/res/values-my-rMM/strings.xml
index f34ca67..9b5f46a 100644
--- a/packages/PrintSpooler/res/values-my-rMM/strings.xml
+++ b/packages/PrintSpooler/res/values-my-rMM/strings.xml
@@ -72,6 +72,10 @@
<string name="recommended_services_title" msgid="3799434882937956924">"အကြံပြုထားသည့် ဝန်ဆောင်မှုများ"</string>
<string name="disabled_services_title" msgid="7313253167968363211">"ပိတ်ထားသည့် ဝန်ဆောင်မှုများ"</string>
<string name="all_services_title" msgid="5578662754874906455">"ဝန်ဆောင်မှုများ အားလုံး"</string>
+ <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+ <item quantity="other">ပုံနှိပ်စက် <xliff:g id="COUNT_1">%1$s</xliff:g> ခုကို ရှာဖွေရန် စနစ်ထည့်သွင်းပါ</item>
+ <item quantity="one">ပုံနှိပ်စက် <xliff:g id="COUNT_0">%1$s</xliff:g> ခုကို ရှာဖွေရန် စနစ်ထည့်သွင်းပါ</item>
+ </plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> ကို စာထုတ်နေပါသည်"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> ကို ပယ်ဖျက်နေပါသည်"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"စာထုတ်စက်မှ အမှား <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-nb/strings.xml b/packages/PrintSpooler/res/values-nb/strings.xml
index 6b74765..82282ba 100644
--- a/packages/PrintSpooler/res/values-nb/strings.xml
+++ b/packages/PrintSpooler/res/values-nb/strings.xml
@@ -72,6 +72,10 @@
<string name="recommended_services_title" msgid="3799434882937956924">"Anbefalte tjenester"</string>
<string name="disabled_services_title" msgid="7313253167968363211">"Tjenester som er slått av"</string>
<string name="all_services_title" msgid="5578662754874906455">"Alle tjenester"</string>
+ <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+ <item quantity="other">Installer for å finne <xliff:g id="COUNT_1">%1$s</xliff:g> printere</item>
+ <item quantity="one">Installer for å finne <xliff:g id="COUNT_0">%1$s</xliff:g> printer</item>
+ </plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"Skriver ut <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"Avbryter <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"Skriverfeil <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-ne-rNP/strings.xml b/packages/PrintSpooler/res/values-ne-rNP/strings.xml
index 8e8bf15..4cf2f51 100644
--- a/packages/PrintSpooler/res/values-ne-rNP/strings.xml
+++ b/packages/PrintSpooler/res/values-ne-rNP/strings.xml
@@ -72,6 +72,10 @@
<string name="recommended_services_title" msgid="3799434882937956924">"सिफारिस गरिएका सेवाहरू"</string>
<string name="disabled_services_title" msgid="7313253167968363211">"असक्षम गरिएका सेवाहरू"</string>
<string name="all_services_title" msgid="5578662754874906455">"सबै सेवाहरू"</string>
+ <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+ <item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> प्रिन्टरहरू पत्ता लगाउनका लागि स्थापना गर्नुहोस्</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%1$s</xliff:g> प्रिन्टर पत्ता लगाउनका लागि स्थापना गर्नुहोस्</item>
+ </plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"प्रिन्ट गरिँदै <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"रद्द गरिँदै <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"प्रिन्टर त्रुटि <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-nl/strings.xml b/packages/PrintSpooler/res/values-nl/strings.xml
index 3c65d8a..83b9a22 100644
--- a/packages/PrintSpooler/res/values-nl/strings.xml
+++ b/packages/PrintSpooler/res/values-nl/strings.xml
@@ -72,6 +72,10 @@
<string name="recommended_services_title" msgid="3799434882937956924">"Aanbevolen services"</string>
<string name="disabled_services_title" msgid="7313253167968363211">"Uitgeschakelde services"</string>
<string name="all_services_title" msgid="5578662754874906455">"Alle services"</string>
+ <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+ <item quantity="other">Installeren om <xliff:g id="COUNT_1">%1$s</xliff:g> printers te vinden</item>
+ <item quantity="one">Installeren om <xliff:g id="COUNT_0">%1$s</xliff:g> printer te vinden</item>
+ </plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> afdrukken"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> annuleren"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"Printerfout <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-pa-rIN/strings.xml b/packages/PrintSpooler/res/values-pa-rIN/strings.xml
index 934123b..5f3366f 100644
--- a/packages/PrintSpooler/res/values-pa-rIN/strings.xml
+++ b/packages/PrintSpooler/res/values-pa-rIN/strings.xml
@@ -72,6 +72,10 @@
<string name="recommended_services_title" msgid="3799434882937956924">"ਸਿਫ਼ਾਰਸ਼ ਕੀਤੀਆਂ ਸੇਵਾਵਾਂ"</string>
<string name="disabled_services_title" msgid="7313253167968363211">"ਅਯੋਗ ਬਣਾਈਆਂ ਗਈਆਂ ਸੇਵਾਵਾਂ"</string>
<string name="all_services_title" msgid="5578662754874906455">"ਸਾਰੀਆਂ ਸੇਵਾਵਾਂ"</string>
+ <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+ <item quantity="one"><xliff:g id="COUNT_1">%1$s</xliff:g> ਪ੍ਰਿੰਟਰ ਖੋਜਣ ਲਈ ਸਥਾਪਤ ਕਰੋ</item>
+ <item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> ਪ੍ਰਿੰਟਰ ਖੋਜਣ ਲਈ ਸਥਾਪਤ ਕਰੋ</item>
+ </plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> ਨੂੰ ਪ੍ਰਿੰਟ ਕਰ ਰਿਹਾ ਹੈ"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> ਨੂੰ ਰੱਦ ਕਰ ਰਿਹਾ ਹੈ"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"ਪ੍ਰਿੰਟਰ ਅਸ਼ੁੱਧੀ <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-pl/strings.xml b/packages/PrintSpooler/res/values-pl/strings.xml
index 80b6070..e7fb7b6 100644
--- a/packages/PrintSpooler/res/values-pl/strings.xml
+++ b/packages/PrintSpooler/res/values-pl/strings.xml
@@ -74,6 +74,12 @@
<string name="recommended_services_title" msgid="3799434882937956924">"Polecane usługi"</string>
<string name="disabled_services_title" msgid="7313253167968363211">"Wyłączone usługi"</string>
<string name="all_services_title" msgid="5578662754874906455">"Wszystkie usługi"</string>
+ <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+ <item quantity="few">Zainstaluj, by wykryć <xliff:g id="COUNT_1">%1$s</xliff:g> drukarki</item>
+ <item quantity="many">Zainstaluj, by wykryć <xliff:g id="COUNT_1">%1$s</xliff:g> drukarek</item>
+ <item quantity="other">Zainstaluj, by wykryć <xliff:g id="COUNT_1">%1$s</xliff:g> drukarki</item>
+ <item quantity="one">Zainstaluj, by wykryć <xliff:g id="COUNT_0">%1$s</xliff:g> drukarkę</item>
+ </plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"Drukowanie: <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"Anulowanie: <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"Błąd drukarki: <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-pt-rBR/strings.xml b/packages/PrintSpooler/res/values-pt-rBR/strings.xml
index 4bd1161..dd8cdb2 100644
--- a/packages/PrintSpooler/res/values-pt-rBR/strings.xml
+++ b/packages/PrintSpooler/res/values-pt-rBR/strings.xml
@@ -72,6 +72,10 @@
<string name="recommended_services_title" msgid="3799434882937956924">"Serviços recomendados"</string>
<string name="disabled_services_title" msgid="7313253167968363211">"Serviços desativados"</string>
<string name="all_services_title" msgid="5578662754874906455">"Todos os serviços"</string>
+ <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+ <item quantity="one">Instale para encontrar <xliff:g id="COUNT_1">%1$s</xliff:g> impressoras</item>
+ <item quantity="other">Instale para encontrar <xliff:g id="COUNT_1">%1$s</xliff:g> impressoras</item>
+ </plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"Imprimindo <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"Cancelando <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"Erro ao imprimir <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-pt-rPT/strings.xml b/packages/PrintSpooler/res/values-pt-rPT/strings.xml
index 7660c5c..c1fe7bf 100644
--- a/packages/PrintSpooler/res/values-pt-rPT/strings.xml
+++ b/packages/PrintSpooler/res/values-pt-rPT/strings.xml
@@ -72,6 +72,10 @@
<string name="recommended_services_title" msgid="3799434882937956924">"Serviços recomendados"</string>
<string name="disabled_services_title" msgid="7313253167968363211">"Serviços desativados"</string>
<string name="all_services_title" msgid="5578662754874906455">"Todos os serviços"</string>
+ <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+ <item quantity="other">Instale para detetar <xliff:g id="COUNT_1">%1$s</xliff:g> impressoras</item>
+ <item quantity="one">Instale para detetar <xliff:g id="COUNT_0">%1$s</xliff:g> impressora</item>
+ </plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"A imprimir <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"A cancelar <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"Erro da impressora <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-pt/strings.xml b/packages/PrintSpooler/res/values-pt/strings.xml
index 4bd1161..dd8cdb2 100644
--- a/packages/PrintSpooler/res/values-pt/strings.xml
+++ b/packages/PrintSpooler/res/values-pt/strings.xml
@@ -72,6 +72,10 @@
<string name="recommended_services_title" msgid="3799434882937956924">"Serviços recomendados"</string>
<string name="disabled_services_title" msgid="7313253167968363211">"Serviços desativados"</string>
<string name="all_services_title" msgid="5578662754874906455">"Todos os serviços"</string>
+ <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+ <item quantity="one">Instale para encontrar <xliff:g id="COUNT_1">%1$s</xliff:g> impressoras</item>
+ <item quantity="other">Instale para encontrar <xliff:g id="COUNT_1">%1$s</xliff:g> impressoras</item>
+ </plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"Imprimindo <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"Cancelando <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"Erro ao imprimir <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-ro/strings.xml b/packages/PrintSpooler/res/values-ro/strings.xml
index dd38c31..b326e09 100644
--- a/packages/PrintSpooler/res/values-ro/strings.xml
+++ b/packages/PrintSpooler/res/values-ro/strings.xml
@@ -73,6 +73,11 @@
<string name="recommended_services_title" msgid="3799434882937956924">"Servicii recomandate"</string>
<string name="disabled_services_title" msgid="7313253167968363211">"Servicii dezactivate"</string>
<string name="all_services_title" msgid="5578662754874906455">"Toate serviciile"</string>
+ <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+ <item quantity="few">Instalați pentru a descoperi <xliff:g id="COUNT_1">%1$s</xliff:g> imprimante</item>
+ <item quantity="other">Instalați pentru a descoperi <xliff:g id="COUNT_1">%1$s</xliff:g> de imprimante</item>
+ <item quantity="one">Instalați pentru a descoperi <xliff:g id="COUNT_0">%1$s</xliff:g> imprimantă</item>
+ </plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"Se printează <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"Se anulează <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"Eroare de printare: <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-ru/strings.xml b/packages/PrintSpooler/res/values-ru/strings.xml
index 6c074ed..5acadbc 100644
--- a/packages/PrintSpooler/res/values-ru/strings.xml
+++ b/packages/PrintSpooler/res/values-ru/strings.xml
@@ -74,6 +74,12 @@
<string name="recommended_services_title" msgid="3799434882937956924">"Рекомендуемые службы"</string>
<string name="disabled_services_title" msgid="7313253167968363211">"Отключенные службы"</string>
<string name="all_services_title" msgid="5578662754874906455">"Все службы печати"</string>
+ <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+ <item quantity="one">Установите, чтобы найти <xliff:g id="COUNT_1">%1$s</xliff:g> принтер</item>
+ <item quantity="few">Установите, чтобы найти <xliff:g id="COUNT_1">%1$s</xliff:g> принтера</item>
+ <item quantity="many">Установите, чтобы найти <xliff:g id="COUNT_1">%1$s</xliff:g> принтеров</item>
+ <item quantity="other">Установите, чтобы найти <xliff:g id="COUNT_1">%1$s</xliff:g> принтера</item>
+ </plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"Печать задания \"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>\"…"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"Отмена задания <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>…"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"Ошибка задания \"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>\""</string>
diff --git a/packages/PrintSpooler/res/values-si-rLK/strings.xml b/packages/PrintSpooler/res/values-si-rLK/strings.xml
index 8278aee..db4c5fd 100644
--- a/packages/PrintSpooler/res/values-si-rLK/strings.xml
+++ b/packages/PrintSpooler/res/values-si-rLK/strings.xml
@@ -72,6 +72,10 @@
<string name="recommended_services_title" msgid="3799434882937956924">"නිර්දේශිත සේවා"</string>
<string name="disabled_services_title" msgid="7313253167968363211">"අබල කළ සේවා"</string>
<string name="all_services_title" msgid="5578662754874906455">"සියලු සේවා"</string>
+ <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+ <item quantity="one">මුද්රණ යන්ත්ර <xliff:g id="COUNT_1">%1$s</xliff:g>ක් සොයා ගැනීමට ස්ථාපනය කරන්න</item>
+ <item quantity="other">මුද්රණ යන්ත්ර <xliff:g id="COUNT_1">%1$s</xliff:g>ක් සොයා ගැනීමට ස්ථාපනය කරන්න</item>
+ </plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> මුද්රණය වේ"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"අවලංගු කෙරේ <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"මුද්රණ දෝෂය <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-sk/strings.xml b/packages/PrintSpooler/res/values-sk/strings.xml
index 610fe99..63ee5e2 100644
--- a/packages/PrintSpooler/res/values-sk/strings.xml
+++ b/packages/PrintSpooler/res/values-sk/strings.xml
@@ -74,6 +74,12 @@
<string name="recommended_services_title" msgid="3799434882937956924">"Odporúčané služby"</string>
<string name="disabled_services_title" msgid="7313253167968363211">"Zakázané služby"</string>
<string name="all_services_title" msgid="5578662754874906455">"Všetky služby"</string>
+ <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+ <item quantity="few">Nainštalujte a objavte <xliff:g id="COUNT_1">%1$s</xliff:g> tlačiarne</item>
+ <item quantity="many">Nainštalujte a objavte <xliff:g id="COUNT_1">%1$s</xliff:g> tlačiarne</item>
+ <item quantity="other">Nainštalujte a objavte <xliff:g id="COUNT_1">%1$s</xliff:g> tlačiarní</item>
+ <item quantity="one">Nainštalujte a objavte <xliff:g id="COUNT_0">%1$s</xliff:g> tlačiareň</item>
+ </plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"Prebieha tlač úlohy <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"Prebieha zrušenie úlohy <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"Chyba tlačiarne – úloha <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-sl/strings.xml b/packages/PrintSpooler/res/values-sl/strings.xml
index b5124b4..f7616db 100644
--- a/packages/PrintSpooler/res/values-sl/strings.xml
+++ b/packages/PrintSpooler/res/values-sl/strings.xml
@@ -74,6 +74,12 @@
<string name="recommended_services_title" msgid="3799434882937956924">"Priporočene storitve"</string>
<string name="disabled_services_title" msgid="7313253167968363211">"Onemogočene storitve"</string>
<string name="all_services_title" msgid="5578662754874906455">"Vse storitve"</string>
+ <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+ <item quantity="one">Namestite za odkrivanje <xliff:g id="COUNT_1">%1$s</xliff:g> tiskalnika</item>
+ <item quantity="two">Namestite za odkrivanje <xliff:g id="COUNT_1">%1$s</xliff:g> tiskalnikov</item>
+ <item quantity="few">Namestite za odkrivanje <xliff:g id="COUNT_1">%1$s</xliff:g> tiskalnikov</item>
+ <item quantity="other">Namestite za odkrivanje <xliff:g id="COUNT_1">%1$s</xliff:g> tiskalnikov</item>
+ </plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"Tiskanje: <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"Preklic: <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"Napaka tiskalnika: <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-sq-rAL/strings.xml b/packages/PrintSpooler/res/values-sq-rAL/strings.xml
index 27bbbf9..f4d2817 100644
--- a/packages/PrintSpooler/res/values-sq-rAL/strings.xml
+++ b/packages/PrintSpooler/res/values-sq-rAL/strings.xml
@@ -72,6 +72,10 @@
<string name="recommended_services_title" msgid="3799434882937956924">"Shërbimet e rekomanduara"</string>
<string name="disabled_services_title" msgid="7313253167968363211">"Shërbimet e çaktivizuara"</string>
<string name="all_services_title" msgid="5578662754874906455">"Të gjitha shërbimet"</string>
+ <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+ <item quantity="other">Instaloje për të zbuluar <xliff:g id="COUNT_1">%1$s</xliff:g> printera</item>
+ <item quantity="one">Instaloje për të zbuluar <xliff:g id="COUNT_0">%1$s</xliff:g> printer</item>
+ </plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"Po printon <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"Po anulon <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"Printeri ndeshi në gabim gjatë punës: <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-sr/strings.xml b/packages/PrintSpooler/res/values-sr/strings.xml
index ea6fcb7..b285044 100644
--- a/packages/PrintSpooler/res/values-sr/strings.xml
+++ b/packages/PrintSpooler/res/values-sr/strings.xml
@@ -73,6 +73,11 @@
<string name="recommended_services_title" msgid="3799434882937956924">"Препоручене услуге"</string>
<string name="disabled_services_title" msgid="7313253167968363211">"Онемогућене услуге"</string>
<string name="all_services_title" msgid="5578662754874906455">"Све услуге"</string>
+ <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+ <item quantity="one">Инсталирајте да бисте открили <xliff:g id="COUNT_1">%1$s</xliff:g> штампач</item>
+ <item quantity="few">Инсталирајте да бисте открили <xliff:g id="COUNT_1">%1$s</xliff:g> штампача</item>
+ <item quantity="other">Инсталирајте да бисте открили <xliff:g id="COUNT_1">%1$s</xliff:g> штампача</item>
+ </plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"Штампа се <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"Отказује се <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"Грешка штампача <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-sv/strings.xml b/packages/PrintSpooler/res/values-sv/strings.xml
index c909e19..4a72800 100644
--- a/packages/PrintSpooler/res/values-sv/strings.xml
+++ b/packages/PrintSpooler/res/values-sv/strings.xml
@@ -72,6 +72,10 @@
<string name="recommended_services_title" msgid="3799434882937956924">"Rekommenderade tjänster"</string>
<string name="disabled_services_title" msgid="7313253167968363211">"Inaktiverade tjänster"</string>
<string name="all_services_title" msgid="5578662754874906455">"Alla tjänster"</string>
+ <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+ <item quantity="other">Installera och hitta <xliff:g id="COUNT_1">%1$s</xliff:g> skrivare</item>
+ <item quantity="one">Installera och hitta <xliff:g id="COUNT_0">%1$s</xliff:g> skrivare</item>
+ </plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"Skriver ut <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"Avbryter <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"Skrivarfel för <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-sw/strings.xml b/packages/PrintSpooler/res/values-sw/strings.xml
index bd14117..34b935d 100644
--- a/packages/PrintSpooler/res/values-sw/strings.xml
+++ b/packages/PrintSpooler/res/values-sw/strings.xml
@@ -72,6 +72,10 @@
<string name="recommended_services_title" msgid="3799434882937956924">"Huduma zinazopendekezwa"</string>
<string name="disabled_services_title" msgid="7313253167968363211">"Huduma ambazo haziruhusiwi"</string>
<string name="all_services_title" msgid="5578662754874906455">"Huduma zote"</string>
+ <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+ <item quantity="other">Sakinisha ili ugundue printa <xliff:g id="COUNT_1">%1$s</xliff:g></item>
+ <item quantity="one">Sakinisha ili ugundue printa <xliff:g id="COUNT_0">%1$s</xliff:g></item>
+ </plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"Inachapisha <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"Inaghairi <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"Hitilafu ya kuchapisha <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-ta-rIN/strings.xml b/packages/PrintSpooler/res/values-ta-rIN/strings.xml
index 782ebf2..22f41bf 100644
--- a/packages/PrintSpooler/res/values-ta-rIN/strings.xml
+++ b/packages/PrintSpooler/res/values-ta-rIN/strings.xml
@@ -72,6 +72,10 @@
<string name="recommended_services_title" msgid="3799434882937956924">"பரிந்துரைக்கப்படும் அச்சுப் பொறிகள்"</string>
<string name="disabled_services_title" msgid="7313253167968363211">"முடக்கப்பட்ட அச்சுப் பொறிகள்"</string>
<string name="all_services_title" msgid="5578662754874906455">"எல்லா அச்சுப் பொறிகளும்"</string>
+ <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+ <item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> பிரிண்டர்களைக் கண்டறிய, நிறுவவும்</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%1$s</xliff:g> பிரிண்டரைக் கண்டறிய, நிறுவவும்</item>
+ </plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> ஐ அச்சிடுகிறது"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> ஐ ரத்துசெய்கிறது"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"பிரிண்டர் பிழை <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-te-rIN/strings.xml b/packages/PrintSpooler/res/values-te-rIN/strings.xml
index ca393c839..1211cfd 100644
--- a/packages/PrintSpooler/res/values-te-rIN/strings.xml
+++ b/packages/PrintSpooler/res/values-te-rIN/strings.xml
@@ -72,6 +72,10 @@
<string name="recommended_services_title" msgid="3799434882937956924">"సిఫార్సు చేయబడిన సేవలు"</string>
<string name="disabled_services_title" msgid="7313253167968363211">"నిలిపివేసిన సేవలు"</string>
<string name="all_services_title" msgid="5578662754874906455">"అన్ని సేవలు"</string>
+ <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+ <item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> ప్రింటర్లను కనుగొనడానికి ఇన్స్టాల్ చేయండి</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%1$s</xliff:g> ప్రింటర్ను కనుగొనడానికి ఇన్స్టాల్ చేయండి</item>
+ </plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>ను ముద్రిస్తోంది"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>ను రద్దు చేస్తోంది"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"ప్రింటర్ లోపం <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-th/strings.xml b/packages/PrintSpooler/res/values-th/strings.xml
index 92b960e..7f99288 100644
--- a/packages/PrintSpooler/res/values-th/strings.xml
+++ b/packages/PrintSpooler/res/values-th/strings.xml
@@ -72,6 +72,10 @@
<string name="recommended_services_title" msgid="3799434882937956924">"บริการที่แนะนำ"</string>
<string name="disabled_services_title" msgid="7313253167968363211">"บริการที่ปิดใช้"</string>
<string name="all_services_title" msgid="5578662754874906455">"บริการทั้งหมด"</string>
+ <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+ <item quantity="other">ติดตั้งเพื่อค้นหาเครื่องพิมพ์ <xliff:g id="COUNT_1">%1$s</xliff:g> เครื่อง</item>
+ <item quantity="one">ติดตั้งเพื่อค้นหาเครื่องพิมพ์ <xliff:g id="COUNT_0">%1$s</xliff:g> เครื่อง</item>
+ </plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"กำลังพิมพ์ <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"กำลังยกเลิก <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"ข้อผิดพลาดเครื่องพิมพ์ <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-tl/strings.xml b/packages/PrintSpooler/res/values-tl/strings.xml
index 5a73659..7b50815 100644
--- a/packages/PrintSpooler/res/values-tl/strings.xml
+++ b/packages/PrintSpooler/res/values-tl/strings.xml
@@ -72,6 +72,10 @@
<string name="recommended_services_title" msgid="3799434882937956924">"Mga inirerekomendang serbisyo"</string>
<string name="disabled_services_title" msgid="7313253167968363211">"Mga naka-disable na serbisyo"</string>
<string name="all_services_title" msgid="5578662754874906455">"Lahat ng serbisyo"</string>
+ <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+ <item quantity="one">I-install upang tumuklas ng <xliff:g id="COUNT_1">%1$s</xliff:g> printer</item>
+ <item quantity="other">I-install upang tumuklas ng <xliff:g id="COUNT_1">%1$s</xliff:g> na printer</item>
+ </plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"Pini-print ang <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"Kinakansela ang <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"Error sa printer <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-tr/strings.xml b/packages/PrintSpooler/res/values-tr/strings.xml
index f17bc9d..1ca722b 100644
--- a/packages/PrintSpooler/res/values-tr/strings.xml
+++ b/packages/PrintSpooler/res/values-tr/strings.xml
@@ -72,6 +72,10 @@
<string name="recommended_services_title" msgid="3799434882937956924">"Önerilen hizmetler"</string>
<string name="disabled_services_title" msgid="7313253167968363211">"Devre dışı bırakılmış hizmetler"</string>
<string name="all_services_title" msgid="5578662754874906455">"Tüm hizmetler"</string>
+ <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+ <item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> yazıcıyı keşfetmek için yükleyin</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%1$s</xliff:g> yazıcıyı keşfetmek için yükleyin</item>
+ </plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> yazdırılıyor"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> iptal ediliyor"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"Yazıcı hatası: <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-uk/strings.xml b/packages/PrintSpooler/res/values-uk/strings.xml
index 9629ad3..8004639 100644
--- a/packages/PrintSpooler/res/values-uk/strings.xml
+++ b/packages/PrintSpooler/res/values-uk/strings.xml
@@ -74,6 +74,12 @@
<string name="recommended_services_title" msgid="3799434882937956924">"Рекомендовані служби"</string>
<string name="disabled_services_title" msgid="7313253167968363211">"Вимкнені служби"</string>
<string name="all_services_title" msgid="5578662754874906455">"Усі служби"</string>
+ <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+ <item quantity="one">Установіть, щоб знайти <xliff:g id="COUNT_1">%1$s</xliff:g> принтер</item>
+ <item quantity="few">Установіть, щоб знайти <xliff:g id="COUNT_1">%1$s</xliff:g> принтери</item>
+ <item quantity="many">Установіть, щоб знайти <xliff:g id="COUNT_1">%1$s</xliff:g> принтерів</item>
+ <item quantity="other">Установіть, щоб знайти <xliff:g id="COUNT_1">%1$s</xliff:g> принтера</item>
+ </plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"Завдання \"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>\" друкується"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"Завдання \"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>\" скасовується"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"Помилка завдання \"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>\""</string>
diff --git a/packages/PrintSpooler/res/values-ur-rPK/strings.xml b/packages/PrintSpooler/res/values-ur-rPK/strings.xml
index 0d01ee2..19e759c 100644
--- a/packages/PrintSpooler/res/values-ur-rPK/strings.xml
+++ b/packages/PrintSpooler/res/values-ur-rPK/strings.xml
@@ -72,6 +72,10 @@
<string name="recommended_services_title" msgid="3799434882937956924">"تجویز کردہ سروسز"</string>
<string name="disabled_services_title" msgid="7313253167968363211">"غیر فعال کردہ سروسز"</string>
<string name="all_services_title" msgid="5578662754874906455">"تمام سروسز"</string>
+ <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+ <item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> پرنٹرز دریافت کرنے کیلئے انسٹال کریں</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%1$s</xliff:g> پرنٹر دریافت کرنے کیلئے انسٹال کریں</item>
+ </plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> پرنٹ کررہا ہے"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> کو منسوخ کر رہا ہے"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"پرنٹر کی خرابی <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-uz-rUZ/strings.xml b/packages/PrintSpooler/res/values-uz-rUZ/strings.xml
index 1f379d9..cf87a74 100644
--- a/packages/PrintSpooler/res/values-uz-rUZ/strings.xml
+++ b/packages/PrintSpooler/res/values-uz-rUZ/strings.xml
@@ -72,6 +72,10 @@
<string name="recommended_services_title" msgid="3799434882937956924">"Tavsiya etilgan xizmatlar"</string>
<string name="disabled_services_title" msgid="7313253167968363211">"O‘chirib qo‘yilgan xizmatlar"</string>
<string name="all_services_title" msgid="5578662754874906455">"Barcha xizmatlar"</string>
+ <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+ <item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> ta printerni topish uchun o‘rnating</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%1$s</xliff:g> ta printerni topish uchun o‘rnating</item>
+ </plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"Chop etilmoqda: <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> bekor qilinmoqda"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"Printerda xatolik: <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-vi/strings.xml b/packages/PrintSpooler/res/values-vi/strings.xml
index b931557..2c1fa27 100644
--- a/packages/PrintSpooler/res/values-vi/strings.xml
+++ b/packages/PrintSpooler/res/values-vi/strings.xml
@@ -72,6 +72,10 @@
<string name="recommended_services_title" msgid="3799434882937956924">"Dịch vụ được đề xuất"</string>
<string name="disabled_services_title" msgid="7313253167968363211">"Dịch vụ đã tắt"</string>
<string name="all_services_title" msgid="5578662754874906455">"Tất cả dịch vụ"</string>
+ <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+ <item quantity="other">Cài đặt để phát hiện <xliff:g id="COUNT_1">%1$s</xliff:g> máy in</item>
+ <item quantity="one">Cài đặt để phát hiện <xliff:g id="COUNT_0">%1$s</xliff:g> máy in</item>
+ </plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"In <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"Hủy <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"Lỗi máy in <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-zh-rCN/strings.xml b/packages/PrintSpooler/res/values-zh-rCN/strings.xml
index e523d48..b350051 100644
--- a/packages/PrintSpooler/res/values-zh-rCN/strings.xml
+++ b/packages/PrintSpooler/res/values-zh-rCN/strings.xml
@@ -72,6 +72,10 @@
<string name="recommended_services_title" msgid="3799434882937956924">"推荐的服务"</string>
<string name="disabled_services_title" msgid="7313253167968363211">"已停用的服务"</string>
<string name="all_services_title" msgid="5578662754874906455">"所有服务"</string>
+ <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+ <item quantity="other">安装即可找到 <xliff:g id="COUNT_1">%1$s</xliff:g> 台打印机</item>
+ <item quantity="one">安装即可找到 <xliff:g id="COUNT_0">%1$s</xliff:g> 台打印机</item>
+ </plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"正在打印“<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>”"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"正在取消打印“<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>”"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"打印机在打印“<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>”时出错"</string>
@@ -99,7 +103,6 @@
<string name="print_error_default_message" msgid="8602678405502922346">"抱歉,操作失败。请重试。"</string>
<string name="print_error_retry" msgid="1426421728784259538">"重试"</string>
<string name="print_error_printer_unavailable" msgid="8985614415253203381">"该打印机目前无法使用。"</string>
- <!-- no translation found for print_cannot_load_page (6179560924492912009) -->
- <skip />
+ <string name="print_cannot_load_page" msgid="6179560924492912009">"无法显示预览"</string>
<string name="print_preparing_preview" msgid="3939930735671364712">"即将显示预览…"</string>
</resources>
diff --git a/packages/PrintSpooler/res/values-zh-rHK/strings.xml b/packages/PrintSpooler/res/values-zh-rHK/strings.xml
index 4411a23..192b41b 100644
--- a/packages/PrintSpooler/res/values-zh-rHK/strings.xml
+++ b/packages/PrintSpooler/res/values-zh-rHK/strings.xml
@@ -72,6 +72,10 @@
<string name="recommended_services_title" msgid="3799434882937956924">"推薦服務"</string>
<string name="disabled_services_title" msgid="7313253167968363211">"已停用的服務"</string>
<string name="all_services_title" msgid="5578662754874906455">"所有服務"</string>
+ <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+ <item quantity="other">安裝即可使用 <xliff:g id="COUNT_1">%1$s</xliff:g> 部印表機</item>
+ <item quantity="one">安裝即可使用 <xliff:g id="COUNT_0">%1$s</xliff:g> 部印表機</item>
+ </plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"正在列印 <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"正在取消 <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"打印機錯誤:<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-zh-rTW/strings.xml b/packages/PrintSpooler/res/values-zh-rTW/strings.xml
index 98126a7..4aa5681 100644
--- a/packages/PrintSpooler/res/values-zh-rTW/strings.xml
+++ b/packages/PrintSpooler/res/values-zh-rTW/strings.xml
@@ -72,6 +72,10 @@
<string name="recommended_services_title" msgid="3799434882937956924">"建議的列印服務"</string>
<string name="disabled_services_title" msgid="7313253167968363211">"已停用的列印服務"</string>
<string name="all_services_title" msgid="5578662754874906455">"所有列印服務"</string>
+ <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+ <item quantity="other">安裝即可使用 <xliff:g id="COUNT_1">%1$s</xliff:g> 個印表機</item>
+ <item quantity="one">安裝即可使用 <xliff:g id="COUNT_0">%1$s</xliff:g> 個印表機</item>
+ </plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"正在列印 <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"正在取消 <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"印表機發生錯誤:<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-zu/strings.xml b/packages/PrintSpooler/res/values-zu/strings.xml
index f2b4990..121022b 100644
--- a/packages/PrintSpooler/res/values-zu/strings.xml
+++ b/packages/PrintSpooler/res/values-zu/strings.xml
@@ -72,6 +72,10 @@
<string name="recommended_services_title" msgid="3799434882937956924">"Amasevisi anconyiwe"</string>
<string name="disabled_services_title" msgid="7313253167968363211">"Amasevisi akhutshaziwe"</string>
<string name="all_services_title" msgid="5578662754874906455">"Onke amasevisi"</string>
+ <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+ <item quantity="one">Faka ukuze uthole amaphrinta we-<xliff:g id="COUNT_1">%1$s</xliff:g></item>
+ <item quantity="other">Faka ukuze uthole amaphrinta we-<xliff:g id="COUNT_1">%1$s</xliff:g></item>
+ </plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"Iphrinta i-<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"Ikhansela i-<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"Iphutha lephrinta ye-<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values/strings.xml b/packages/PrintSpooler/res/values/strings.xml
index 2f24d2c..2836adb 100644
--- a/packages/PrintSpooler/res/values/strings.xml
+++ b/packages/PrintSpooler/res/values/strings.xml
@@ -185,6 +185,12 @@
<!-- Label for the list item that links to the list of all print services. [CHAR LIMIT=50] -->
<string name="all_services_title">All services</string>
+ <!-- Subtitle for a print service recommendation. [CHAR LIMIT=50] -->
+ <plurals name="print_services_recommendation_subtitle">
+ <item quantity="one">Install to discover <xliff:g id="count" example="1">%1$s</xliff:g> printer</item>
+ <item quantity="other">Install to discover <xliff:g id="count" example="2">%1$s</xliff:g> printers</item>
+ </plurals>
+
<!-- Notifications -->
<!-- Template for the notification label for a printing print job. [CHAR LIMIT=25] -->
diff --git a/packages/PrintSpooler/src/com/android/printspooler/model/RemotePrintDocument.java b/packages/PrintSpooler/src/com/android/printspooler/model/RemotePrintDocument.java
index 2d3935b..99145b7b 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/model/RemotePrintDocument.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/model/RemotePrintDocument.java
@@ -178,6 +178,8 @@
}
if (mState == STATE_FAILED) {
Log.w(LOG_TAG, "Failed before start.");
+ } else if (mState == STATE_DESTROYED) {
+ Log.w(LOG_TAG, "Destroyed before start.");
} else {
if (mState != STATE_INITIAL) {
throw new IllegalStateException("Cannot start in state:" + stateToString(mState));
@@ -267,7 +269,7 @@
}
if (mState != STATE_STARTED && mState != STATE_UPDATED
&& mState != STATE_FAILED && mState != STATE_CANCELING
- && mState != STATE_CANCELED) {
+ && mState != STATE_CANCELED && mState != STATE_DESTROYED) {
throw new IllegalStateException("Cannot finish in state:"
+ stateToString(mState));
}
diff --git a/packages/PrintSpooler/src/com/android/printspooler/renderer/PdfManipulationService.java b/packages/PrintSpooler/src/com/android/printspooler/renderer/PdfManipulationService.java
index af4c347..0feda92 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/renderer/PdfManipulationService.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/renderer/PdfManipulationService.java
@@ -244,9 +244,20 @@
ranges = PageRangeUtils.normalize(ranges);
+ int lastPageIdx = mEditor.getPageCount() - 1;
+
final int rangeCount = ranges.length;
for (int i = rangeCount - 1; i >= 0; i--) {
PageRange range = ranges[i];
+
+ // Ignore removal of pages that are outside the document
+ if (range.getEnd() > lastPageIdx) {
+ if (range.getStart() > lastPageIdx) {
+ continue;
+ }
+ range = new PageRange(range.getStart(), lastPageIdx);
+ }
+
for (int j = range.getEnd(); j >= range.getStart(); j--) {
mEditor.removePage(j);
}
diff --git a/packages/PrintSpooler/src/com/android/printspooler/ui/AddPrinterActivity.java b/packages/PrintSpooler/src/com/android/printspooler/ui/AddPrinterActivity.java
index f2b3e6e..42ef10e 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/ui/AddPrinterActivity.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/ui/AddPrinterActivity.java
@@ -30,10 +30,13 @@
import android.net.Uri;
import android.os.Bundle;
import android.print.PrintManager;
+import android.printservice.recommendation.RecommendationInfo;
+import android.print.PrintServiceRecommendationsLoader;
import android.print.PrintServicesLoader;
import android.printservice.PrintServiceInfo;
import android.provider.Settings;
import android.text.TextUtils;
+import android.util.ArraySet;
import android.util.Log;
import android.util.Pair;
import android.view.View;
@@ -45,8 +48,10 @@
import android.widget.TextView;
import com.android.printspooler.R;
+import java.text.Collator;
import java.util.ArrayList;
import java.util.Collections;
+import java.util.Comparator;
import java.util.List;
/**
@@ -57,31 +62,38 @@
* when the item is clicked.</li>
* <li>{@link #mDisabledServicesAdapter} for all disabled services. Once clicked the settings page
* for this service is opened.</li>
- * <li>{@link RecommendedServicesAdapter} for a link to all services. If this item is clicked
+ * <li>{@link #mRecommendedServicesAdapter} for a link to all services. If this item is clicked
* the market app is opened to show all print services.</li>
* </ul>
*/
-public class AddPrinterActivity extends ListActivity implements
- LoaderManager.LoaderCallbacks<List<PrintServiceInfo>>,
- AdapterView.OnItemClickListener {
+public class AddPrinterActivity extends ListActivity implements AdapterView.OnItemClickListener {
private static final String LOG_TAG = "AddPrinterActivity";
/** Ids for the loaders */
private static final int LOADER_ID_ENABLED_SERVICES = 1;
private static final int LOADER_ID_DISABLED_SERVICES = 2;
+ private static final int LOADER_ID_RECOMMENDED_SERVICES = 3;
+ private static final int LOADER_ID_ALL_SERVICES = 4;
/**
* The enabled services list. This is filled from the {@link #LOADER_ID_ENABLED_SERVICES}
- * loader in {@link #onLoadFinished}.
+ * loader in {@link PrintServiceInfoLoaderCallbacks#onLoadFinished}.
*/
private EnabledServicesAdapter mEnabledServicesAdapter;
/**
* The disabled services list. This is filled from the {@link #LOADER_ID_DISABLED_SERVICES}
- * loader in {@link #onLoadFinished}.
+ * loader in {@link PrintServiceInfoLoaderCallbacks#onLoadFinished}.
*/
private DisabledServicesAdapter mDisabledServicesAdapter;
+ /**
+ * The recommended services list. This is filled from the
+ * {@link #LOADER_ID_RECOMMENDED_SERVICES} loader in
+ * {@link PrintServicePrintServiceRecommendationLoaderCallbacks#onLoadFinished}.
+ */
+ private RecommendedServicesAdapter mRecommendedServicesAdapter;
+
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -90,36 +102,116 @@
mEnabledServicesAdapter = new EnabledServicesAdapter();
mDisabledServicesAdapter = new DisabledServicesAdapter();
+ mRecommendedServicesAdapter = new RecommendedServicesAdapter();
ArrayList<ActionAdapter> adapterList = new ArrayList<>(3);
adapterList.add(mEnabledServicesAdapter);
- adapterList.add(new RecommendedServicesAdapter());
+ adapterList.add(mRecommendedServicesAdapter);
adapterList.add(mDisabledServicesAdapter);
setListAdapter(new CombinedAdapter(adapterList));
getListView().setOnItemClickListener(this);
- getLoaderManager().initLoader(LOADER_ID_ENABLED_SERVICES, null, this);
- getLoaderManager().initLoader(LOADER_ID_DISABLED_SERVICES, null, this);
- // TODO: Load recommended services
+ PrintServiceInfoLoaderCallbacks printServiceLoaderCallbacks =
+ new PrintServiceInfoLoaderCallbacks();
+
+ getLoaderManager().initLoader(LOADER_ID_ENABLED_SERVICES, null, printServiceLoaderCallbacks);
+ getLoaderManager().initLoader(LOADER_ID_DISABLED_SERVICES, null, printServiceLoaderCallbacks);
+ getLoaderManager().initLoader(LOADER_ID_RECOMMENDED_SERVICES, null,
+ new PrintServicePrintServiceRecommendationLoaderCallbacks());
+ getLoaderManager().initLoader(LOADER_ID_ALL_SERVICES, null, printServiceLoaderCallbacks);
}
- @Override
- public Loader<List<PrintServiceInfo>> onCreateLoader(int id, Bundle args) {
- switch (id) {
- case LOADER_ID_ENABLED_SERVICES:
- return new PrintServicesLoader(
- (PrintManager) getSystemService(Context.PRINT_SERVICE), this,
- PrintManager.ENABLED_SERVICES);
- case LOADER_ID_DISABLED_SERVICES:
- return new PrintServicesLoader(
- (PrintManager) getSystemService(Context.PRINT_SERVICE), this,
- PrintManager.DISABLED_SERVICES);
- // TODO: Load recommended services
- default:
- // not reached
- return null;
+ /**
+ * Callbacks for the loaders operating on list of {@link PrintServiceInfo print service infos}.
+ */
+ private class PrintServiceInfoLoaderCallbacks implements
+ LoaderManager.LoaderCallbacks<List<PrintServiceInfo>> {
+ @Override
+ public Loader<List<PrintServiceInfo>> onCreateLoader(int id, Bundle args) {
+ switch (id) {
+ case LOADER_ID_ENABLED_SERVICES:
+ return new PrintServicesLoader(
+ (PrintManager) getSystemService(Context.PRINT_SERVICE),
+ AddPrinterActivity.this, PrintManager.ENABLED_SERVICES);
+ case LOADER_ID_DISABLED_SERVICES:
+ return new PrintServicesLoader(
+ (PrintManager) getSystemService(Context.PRINT_SERVICE),
+ AddPrinterActivity.this, PrintManager.DISABLED_SERVICES);
+ case LOADER_ID_ALL_SERVICES:
+ return new PrintServicesLoader(
+ (PrintManager) getSystemService(Context.PRINT_SERVICE),
+ AddPrinterActivity.this, PrintManager.ALL_SERVICES);
+ default:
+ // not reached
+ return null;
+ }
+ }
+
+
+ @Override
+ public void onLoadFinished(Loader<List<PrintServiceInfo>> loader,
+ List<PrintServiceInfo> data) {
+ switch (loader.getId()) {
+ case LOADER_ID_ENABLED_SERVICES:
+ mEnabledServicesAdapter.updateData(data);
+ break;
+ case LOADER_ID_DISABLED_SERVICES:
+ mDisabledServicesAdapter.updateData(data);
+ break;
+ case LOADER_ID_ALL_SERVICES:
+ mRecommendedServicesAdapter.updateInstalledServices(data);
+ default:
+ // not reached
+ }
+ }
+
+ @Override
+ public void onLoaderReset(Loader<List<PrintServiceInfo>> loader) {
+ if (!isFinishing()) {
+ switch (loader.getId()) {
+ case LOADER_ID_ENABLED_SERVICES:
+ mEnabledServicesAdapter.updateData(null);
+ break;
+ case LOADER_ID_DISABLED_SERVICES:
+ mDisabledServicesAdapter.updateData(null);
+ break;
+ case LOADER_ID_ALL_SERVICES:
+ mRecommendedServicesAdapter.updateInstalledServices(null);
+ break;
+ default:
+ // not reached
+ }
+ }
+ }
+ }
+
+ /**
+ * Callbacks for the loaders operating on list of {@link RecommendationInfo print service
+ * recommendations}.
+ */
+ private class PrintServicePrintServiceRecommendationLoaderCallbacks implements
+ LoaderManager.LoaderCallbacks<List<RecommendationInfo>> {
+ @Override
+ public Loader<List<RecommendationInfo>> onCreateLoader(int id, Bundle args) {
+ return new PrintServiceRecommendationsLoader(
+ (PrintManager) getSystemService(Context.PRINT_SERVICE),
+ AddPrinterActivity.this);
+ }
+
+
+ @Override
+ public void onLoadFinished(Loader<List<RecommendationInfo>> loader,
+ List<RecommendationInfo> data) {
+ mRecommendedServicesAdapter.updateRecommendations(data);
+ }
+
+ @Override
+ public void onLoaderReset(Loader<List<RecommendationInfo>> loader) {
+ if (!isFinishing()) {
+ mRecommendedServicesAdapter.updateRecommendations(null);
+ }
}
}
@@ -128,39 +220,6 @@
((ActionAdapter) getListAdapter()).performAction(position);
}
- @Override
- public void onLoadFinished(Loader<List<PrintServiceInfo>> loader,
- List<PrintServiceInfo> data) {
- switch (loader.getId()) {
- case LOADER_ID_ENABLED_SERVICES:
- mEnabledServicesAdapter.updateData(data);
- break;
- case LOADER_ID_DISABLED_SERVICES:
- mDisabledServicesAdapter.updateData(data);
- break;
- // TODO: Load recommended services
- default:
- // not reached
- }
- }
-
- @Override
- public void onLoaderReset(Loader<List<PrintServiceInfo>> loader) {
- if (!isFinishing()) {
- switch (loader.getId()) {
- case LOADER_ID_ENABLED_SERVICES:
- mEnabledServicesAdapter.updateData(null);
- break;
- case LOADER_ID_DISABLED_SERVICES:
- mDisabledServicesAdapter.updateData(null);
- break;
- // TODO: Reset recommended services
- default:
- // not reached
- }
- }
- }
-
/**
* Marks an adapter that can can perform an action for a position in it's list.
*/
@@ -490,28 +549,65 @@
* Adapter for the recommended services.
*/
private class RecommendedServicesAdapter extends ActionAdapter {
+ /** Package names of all installed print services */
+ private @NonNull final ArraySet<String> mInstalledServices;
+
+ /** All print service recommendations */
+ private @Nullable List<RecommendationInfo> mRecommendations;
+
+ /**
+ * Sorted print service recommendations for services that are not installed
+ *
+ * @see #filterRecommendations
+ */
+ private @Nullable List<RecommendationInfo> mFilteredRecommendations;
+
+ /**
+ * Create a new adapter.
+ */
+ private RecommendedServicesAdapter() {
+ mInstalledServices = new ArraySet<>();
+ }
+
@Override
public int getCount() {
- return 2;
+ if (mFilteredRecommendations == null) {
+ return 2;
+ } else {
+ return mFilteredRecommendations.size() + 2;
+ }
}
@Override
public int getViewTypeCount() {
- return 2;
+ return 3;
+ }
+
+ /**
+ * @return The position the all services link is at.
+ */
+ private int getAllServicesPos() {
+ return getCount() - 1;
}
@Override
public int getItemViewType(int position) {
if (position == 0) {
return 0;
- } else {
+ } else if (getAllServicesPos() == position) {
return 1;
+ } else {
+ return 2;
}
}
@Override
public Object getItem(int position) {
- return null;
+ if (position == 0 || position == getAllServicesPos()) {
+ return null;
+ } else {
+ return mFilteredRecommendations.get(position - 1);
+ }
}
@Override
@@ -531,11 +627,27 @@
.setText(R.string.recommended_services_title);
return convertView;
- }
+ } else if (position == getAllServicesPos()) {
+ if (convertView == null) {
+ convertView = getLayoutInflater().inflate(R.layout.all_print_services_list_item,
+ parent, false);
+ }
+ } else {
+ RecommendationInfo recommendation = (RecommendationInfo) getItem(position);
- if (convertView == null) {
- convertView = getLayoutInflater().inflate(R.layout.all_print_services_list_item,
- parent, false);
+ if (convertView == null) {
+ convertView = getLayoutInflater().inflate(
+ R.layout.print_service_recommendations_list_item, parent, false);
+ }
+
+ ((TextView) convertView.findViewById(R.id.title)).setText(recommendation.getName());
+
+ ((TextView) convertView.findViewById(R.id.subtitle)).setText(getResources()
+ .getQuantityString(R.plurals.print_services_recommendation_subtitle,
+ recommendation.getNumDiscoveredPrinters(),
+ recommendation.getNumDiscoveredPrinters()));
+
+ return convertView;
}
return convertView;
@@ -548,16 +660,107 @@
@Override
public void performAction(@IntRange(from = 0) int position) {
- String searchUri = Settings.Secure
- .getString(getContentResolver(), Settings.Secure.PRINT_SERVICE_SEARCH_URI);
+ if (position == getAllServicesPos()) {
+ String searchUri = Settings.Secure
+ .getString(getContentResolver(), Settings.Secure.PRINT_SERVICE_SEARCH_URI);
- if (searchUri != null) {
+ if (searchUri != null) {
+ try {
+ startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(searchUri)));
+ } catch (ActivityNotFoundException e) {
+ Log.e(LOG_TAG, "Cannot start market", e);
+ }
+ }
+ } else {
+ RecommendationInfo recommendation = (RecommendationInfo) getItem(position);
+
try {
- startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(searchUri)));
+ startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(getString(
+ R.string.uri_package_details, recommendation.getPackageName()))));
} catch (ActivityNotFoundException e) {
Log.e(LOG_TAG, "Cannot start market", e);
}
}
}
+
+ /**
+ * Filter recommended services.
+ */
+ private void filterRecommendations() {
+ if (mRecommendations == null) {
+ mFilteredRecommendations = null;
+ } else {
+ mFilteredRecommendations = new ArrayList<>();
+
+ // Filter out recommendations for already installed services
+ final int numRecommendations = mRecommendations.size();
+ for (int i = 0; i < numRecommendations; i++) {
+ RecommendationInfo recommendation = mRecommendations.get(i);
+
+ if (!mInstalledServices.contains(recommendation.getPackageName())) {
+ mFilteredRecommendations.add(recommendation);
+ }
+ }
+ }
+
+ notifyDataSetChanged();
+ }
+
+ /**
+ * Update the installed print services.
+ *
+ * @param services The new set of services
+ */
+ public void updateInstalledServices(List<PrintServiceInfo> services) {
+ mInstalledServices.clear();
+
+ final int numServices = services.size();
+ for (int i = 0; i < numServices; i++) {
+ mInstalledServices.add(services.get(i).getComponentName().getPackageName());
+ }
+
+ filterRecommendations();
+ }
+
+ /**
+ * Update the recommended print services.
+ *
+ * @param recommendations The new set of recommendations
+ */
+ public void updateRecommendations(List<RecommendationInfo> recommendations) {
+ if (recommendations != null) {
+ final Collator collator = Collator.getInstance();
+
+ // Sort recommendations (early conditions are more important)
+ // - higher number of discovered printers first
+ // - single vendor services first
+ // - alphabetically
+ Collections.sort(recommendations,
+ new Comparator<RecommendationInfo>() {
+ @Override public int compare(RecommendationInfo o1,
+ RecommendationInfo o2) {
+ if (o1.getNumDiscoveredPrinters() !=
+ o2.getNumDiscoveredPrinters()) {
+ return o2.getNumDiscoveredPrinters() -
+ o1.getNumDiscoveredPrinters();
+ } else if (o1.recommendsMultiVendorService()
+ != o2.recommendsMultiVendorService()) {
+ if (o1.recommendsMultiVendorService()) {
+ return 1;
+ } else {
+ return -1;
+ }
+ } else {
+ return collator.compare(o1.getName().toString(),
+ o2.getName().toString());
+ }
+ }
+ });
+ }
+
+ mRecommendations = recommendations;
+
+ filterRecommendations();
+ }
}
}
diff --git a/packages/PrintSpooler/src/com/android/printspooler/ui/FusedPrintersProvider.java b/packages/PrintSpooler/src/com/android/printspooler/ui/FusedPrintersProvider.java
index 3b5513a..7935440 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/ui/FusedPrintersProvider.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/ui/FusedPrintersProvider.java
@@ -267,9 +267,12 @@
// The contract is that if we already have a valid,
// result the we have to deliver it immediately.
- if (!mPrinters.isEmpty()) {
- deliverResult(new ArrayList<>(mPrinters));
- }
+ (new Handler(Looper.getMainLooper())).post(new Runnable() {
+ @Override public void run() {
+ deliverResult(new ArrayList<>(mPrinters));
+ }
+ });
+
// Always load the data to ensure discovery period is
// started and to make sure obsolete printers are updated.
onForceLoad();
diff --git a/packages/PrintSpooler/src/com/android/printspooler/ui/PageAdapter.java b/packages/PrintSpooler/src/com/android/printspooler/ui/PageAdapter.java
index eebb60c..c1a3f86 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/ui/PageAdapter.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/ui/PageAdapter.java
@@ -206,6 +206,7 @@
int documentPageCount, MediaSize mediaSize, Margins minMargins) {
boolean documentChanged = false;
boolean updatePreviewAreaAndPageSize = false;
+ boolean clearSelectedPages = false;
// If the app does not tell how many pages are in the document we cannot
// optimize and ask for all pages whose count we get from the renderer.
@@ -225,30 +226,41 @@
}
}
- if (!Arrays.equals(mSelectedPages, selectedPages)) {
- mSelectedPages = selectedPages;
- mSelectedPageCount = PageRangeUtils.getNormalizedPageCount(
- mSelectedPages, documentPageCount);
- setConfirmedPages(mSelectedPages, documentPageCount);
- updatePreviewAreaAndPageSize = true;
- documentChanged = true;
- }
-
if (mDocumentPageCount != documentPageCount) {
mDocumentPageCount = documentPageCount;
documentChanged = true;
+ clearSelectedPages = true;
}
if (mMediaSize == null || !mMediaSize.equals(mediaSize)) {
mMediaSize = mediaSize;
updatePreviewAreaAndPageSize = true;
documentChanged = true;
+
+ clearSelectedPages = true;
}
if (mMinMargins == null || !mMinMargins.equals(minMargins)) {
mMinMargins = minMargins;
updatePreviewAreaAndPageSize = true;
documentChanged = true;
+
+ clearSelectedPages = true;
+ }
+
+ if (clearSelectedPages) {
+ mSelectedPages = PageRange.ALL_PAGES_ARRAY;
+ mSelectedPageCount = documentPageCount;
+ setConfirmedPages(mSelectedPages, documentPageCount);
+ updatePreviewAreaAndPageSize = true;
+ documentChanged = true;
+ } else if (!Arrays.equals(mSelectedPages, selectedPages)) {
+ mSelectedPages = selectedPages;
+ mSelectedPageCount = PageRangeUtils.getNormalizedPageCount(
+ mSelectedPages, documentPageCount);
+ setConfirmedPages(mSelectedPages, documentPageCount);
+ updatePreviewAreaAndPageSize = true;
+ documentChanged = true;
}
// If *all pages* is selected we need to convert that to absolute
diff --git a/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java b/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
index a24d664..cde0fa3 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
@@ -128,8 +128,6 @@
private static final boolean DEBUG = false;
- public static final String INTENT_EXTRA_PRINTER_ID = "INTENT_EXTRA_PRINTER_ID";
-
private static final String FRAGMENT_TAG = "FRAGMENT_TAG";
private static final String HAS_PRINTED_PREF = "has_printed";
@@ -176,8 +174,6 @@
"[\\s]*[0-9]+[\\-]?[\\s]*[0-9]*[\\s]*?(([,])"
+ "[\\s]*[0-9]+[\\s]*[\\-]?[\\s]*[0-9]*[\\s]*|[\\s]*)+");
- public static final PageRange[] ALL_PAGES_ARRAY = new PageRange[]{PageRange.ALL_PAGES};
-
private boolean mIsOptionsUiBound = false;
private final PrinterAvailabilityDetector mPrinterAvailabilityDetector =
@@ -480,7 +476,7 @@
}
private void onPrintDocumentError(String message) {
- mProgressMessageController.cancel();
+ setState(mProgressMessageController.cancel());
ensureErrorUiShown(null, PrintErrorFragment.ACTION_RETRY);
setState(STATE_UPDATE_FAILED);
@@ -506,7 +502,7 @@
Log.i(LOG_TAG, "onUpdateCanceled()");
}
- mProgressMessageController.cancel();
+ setState(mProgressMessageController.cancel());
ensurePreviewUiShown();
switch (mState) {
@@ -528,7 +524,7 @@
Log.i(LOG_TAG, "onUpdateCompleted()");
}
- mProgressMessageController.cancel();
+ setState(mProgressMessageController.cancel());
ensurePreviewUiShown();
// Update the print job with the info for the written document. The page
@@ -576,7 +572,7 @@
Log.i(LOG_TAG, "onUpdateFailed()");
}
- mProgressMessageController.cancel();
+ setState(mProgressMessageController.cancel());
ensureErrorUiShown(error, PrintErrorFragment.ACTION_RETRY);
if (mState == STATE_CREATE_FILE_FAILED
@@ -597,14 +593,6 @@
@Override
public void onOptionsClosed() {
- PageRange[] selectedPages = computeSelectedPages();
- if (!Arrays.equals(mSelectedPages, selectedPages)) {
- mSelectedPages = selectedPages;
-
- // Update preview.
- updatePrintPreviewController(false);
- }
-
// Make sure the IME is not on the way of preview as
// the user may have used it to type copies or range.
InputMethodManager imm = getSystemService(InputMethodManager.class);
@@ -717,21 +705,17 @@
private void onSelectPrinterActivityResult(int resultCode, Intent data) {
if (resultCode == RESULT_OK && data != null) {
- PrinterId printerId = data.getParcelableExtra(INTENT_EXTRA_PRINTER_ID);
- if (printerId != null) {
- mDestinationSpinnerAdapter.ensurePrinterInVisibleAdapterPosition(printerId);
- final int index = mDestinationSpinnerAdapter.getPrinterIndex(printerId);
- if (index != AdapterView.INVALID_POSITION) {
- mDestinationSpinner.setSelection(index);
- return;
- }
+ PrinterInfo printerInfo = data.getParcelableExtra(
+ SelectPrinterActivity.INTENT_EXTRA_PRINTER);
+ if (printerInfo != null) {
+ mCurrentPrinter = printerInfo;
+ mDestinationSpinnerAdapter.ensurePrinterInVisibleAdapterPosition(printerInfo);
}
}
if (mCurrentPrinter != null) {
- PrinterId printerId = mCurrentPrinter.getId();
- final int index = mDestinationSpinnerAdapter.getPrinterIndex(printerId);
- mDestinationSpinner.setSelection(index);
+ // Trigger PrintersObserver.onChanged() to adjust selection back to current printer
+ mDestinationSpinnerAdapter.notifyDataSetChanged();
}
}
@@ -950,7 +934,7 @@
mSelectedPages = selectedPages;
mPrintJob.setPages(selectedPages);
- if (Arrays.equals(selectedPages, ALL_PAGES_ARRAY)) {
+ if (Arrays.equals(selectedPages, PageRange.ALL_PAGES_ARRAY)) {
if (mRangeOptionsSpinner.getSelectedItemPosition() != 0) {
mRangeOptionsSpinner.setSelection(0);
mPageRangeEditText.setText("");
@@ -1049,7 +1033,22 @@
}
}
+ /**
+ * Clear the selected page range and update the preview if needed.
+ */
+ private void clearPageRanges() {
+ mRangeOptionsSpinner.setSelection(0);
+ mPageRangeEditText.setError(null);
+ mPageRangeEditText.setText("");
+ mSelectedPages = PageRange.ALL_PAGES_ARRAY;
+
+ if (!Arrays.equals(mSelectedPages, mPrintPreviewController.getSelectedPages())) {
+ updatePrintPreviewController(false);
+ }
+ }
+
private void updatePrintAttributesFromCapabilities(PrinterCapabilitiesInfo capabilities) {
+ boolean clearRanges = false;
PrintAttributes defaults = capabilities.getDefaults();
// Sort the media sizes based on the current locale.
@@ -1061,6 +1060,7 @@
// Media size.
MediaSize currMediaSize = attributes.getMediaSize();
if (currMediaSize == null) {
+ clearRanges = true;
attributes.setMediaSize(defaults.getMediaSize());
} else {
MediaSize newMediaSize = null;
@@ -1079,6 +1079,7 @@
}
// If we did not find the current media size fall back to default.
if (newMediaSize == null) {
+ clearRanges = true;
newMediaSize = defaults.getMediaSize();
}
@@ -1110,7 +1111,14 @@
}
// Margins.
+ if (!Objects.equals(attributes.getMinMargins(), defaults.getMinMargins())) {
+ clearRanges = true;
+ }
attributes.setMinMargins(defaults.getMinMargins());
+
+ if (clearRanges) {
+ clearPageRanges();
+ }
}
private boolean updateDocument(boolean clearLastError) {
@@ -1161,6 +1169,18 @@
doFinish();
}
+ /**
+ * Update the selected pages from the text field.
+ */
+ private void updateSelectedPagesFromTextField() {
+ PageRange[] selectedPages = computeSelectedPages();
+ if (!Arrays.equals(mSelectedPages, selectedPages)) {
+ mSelectedPages = selectedPages;
+ // Update preview.
+ updatePrintPreviewController(false);
+ }
+ }
+
private void confirmPrint() {
setState(STATE_PRINT_CONFIRMED);
@@ -1170,14 +1190,10 @@
addCurrentPrinterToHistory();
setUserPrinted();
- PageRange[] selectedPages = computeSelectedPages();
- if (!Arrays.equals(mSelectedPages, selectedPages)) {
- mSelectedPages = selectedPages;
- // Update preview.
- updatePrintPreviewController(false);
- }
-
+ // updateSelectedPagesFromTextField migth update the preview, hence apply the preview first
updateSelectedPagesFromPreview();
+ updateSelectedPagesFromTextField();
+
mPrintPreviewController.closeOptions();
if (canUpdateDocument()) {
@@ -1262,6 +1278,7 @@
// Page range
mPageRangeTitle = (TextView) findViewById(R.id.page_range_title);
mPageRangeEditText = (EditText) findViewById(R.id.page_range_edittext);
+ mPageRangeEditText.setVisibility(View.INVISIBLE);
mPageRangeEditText.setOnFocusChangeListener(mSelectAllOnFocusListener);
mPageRangeEditText.addTextChangedListener(new RangeTextWatcher());
@@ -1476,6 +1493,10 @@
cancelPrint();
}
} else if (view == mMoreOptionsButton) {
+ // The selected pages is only applied once the user leaves the text field. A click
+ // on this button, does not count as leaving.
+ updateSelectedPagesFromTextField();
+
if (mCurrentPrinter != null) {
startAdvancedPrintOptionsActivity(mCurrentPrinter);
}
@@ -1753,36 +1774,38 @@
// Range options
PrintDocumentInfo info = mPrintedDocument.getDocumentInfo().info;
final int pageCount = getAdjustedPageCount(info);
- if (info != null && pageCount > 0) {
- if (pageCount == 1) {
- mRangeOptionsSpinner.setEnabled(false);
- } else {
- mRangeOptionsSpinner.setEnabled(true);
- if (mRangeOptionsSpinner.getSelectedItemPosition() > 0) {
- if (!mPageRangeEditText.isEnabled()) {
- mPageRangeEditText.setEnabled(true);
- mPageRangeEditText.setVisibility(View.VISIBLE);
- mPageRangeTitle.setVisibility(View.VISIBLE);
- mPageRangeEditText.requestFocus();
- InputMethodManager imm = (InputMethodManager)
- getSystemService(Context.INPUT_METHOD_SERVICE);
- imm.showSoftInput(mPageRangeEditText, 0);
- }
+ if (pageCount > 0) {
+ if (info != null) {
+ if (pageCount == 1) {
+ mRangeOptionsSpinner.setEnabled(false);
} else {
- mPageRangeEditText.setEnabled(false);
- mPageRangeEditText.setVisibility(View.INVISIBLE);
- mPageRangeTitle.setVisibility(View.INVISIBLE);
+ mRangeOptionsSpinner.setEnabled(true);
+ if (mRangeOptionsSpinner.getSelectedItemPosition() > 0) {
+ if (!mPageRangeEditText.isEnabled()) {
+ mPageRangeEditText.setEnabled(true);
+ mPageRangeEditText.setVisibility(View.VISIBLE);
+ mPageRangeTitle.setVisibility(View.VISIBLE);
+ mPageRangeEditText.requestFocus();
+ InputMethodManager imm = (InputMethodManager)
+ getSystemService(Context.INPUT_METHOD_SERVICE);
+ imm.showSoftInput(mPageRangeEditText, 0);
+ }
+ } else {
+ mPageRangeEditText.setEnabled(false);
+ mPageRangeEditText.setVisibility(View.INVISIBLE);
+ mPageRangeTitle.setVisibility(View.INVISIBLE);
+ }
}
+ } else {
+ if (mRangeOptionsSpinner.getSelectedItemPosition() != 0) {
+ mRangeOptionsSpinner.setSelection(0);
+ mPageRangeEditText.setText("");
+ }
+ mRangeOptionsSpinner.setEnabled(false);
+ mPageRangeEditText.setEnabled(false);
+ mPageRangeEditText.setVisibility(View.INVISIBLE);
+ mPageRangeTitle.setVisibility(View.INVISIBLE);
}
- } else {
- if (mRangeOptionsSpinner.getSelectedItemPosition() != 0) {
- mRangeOptionsSpinner.setSelection(0);
- mPageRangeEditText.setText("");
- }
- mRangeOptionsSpinner.setEnabled(false);
- mPageRangeEditText.setEnabled(false);
- mPageRangeEditText.setVisibility(View.INVISIBLE);
- mPageRangeTitle.setVisibility(View.INVISIBLE);
}
final int newPageCount = getAdjustedPageCount(info);
@@ -1933,7 +1956,7 @@
return PageRangeUtils.normalize(pageRangesArray);
}
- return ALL_PAGES_ARRAY;
+ return PageRange.ALL_PAGES_ARRAY;
}
private int getAdjustedPageCount(PrintDocumentInfo info) {
@@ -2055,8 +2078,9 @@
mSpoolerProvider.destroy();
}
+ setState(mProgressMessageController.cancel());
+
if (mState != STATE_INITIALIZING) {
- mProgressMessageController.cancel();
mPrintedDocument.finish();
mPrintedDocument.destroy();
mPrintPreviewController.destroy(new Runnable() {
@@ -2229,23 +2253,36 @@
return AdapterView.INVALID_POSITION;
}
- public void ensurePrinterInVisibleAdapterPosition(PrinterId printerId) {
+ public void ensurePrinterInVisibleAdapterPosition(PrinterInfo printer) {
final int printerCount = mPrinterHolders.size();
+ boolean isKnownPrinter = false;
for (int i = 0; i < printerCount; i++) {
PrinterHolder printerHolder = mPrinterHolders.get(i);
- if (printerHolder.printer.getId().equals(printerId)) {
+
+ if (printerHolder.printer.getId().equals(printer.getId())) {
+ isKnownPrinter = true;
+
// If already in the list - do nothing.
if (i < getCount() - 2) {
- return;
+ break;
}
// Else replace the last one (two items are not printers).
final int lastPrinterIndex = getCount() - 3;
mPrinterHolders.set(i, mPrinterHolders.get(lastPrinterIndex));
mPrinterHolders.set(lastPrinterIndex, printerHolder);
- notifyDataSetChanged();
- return;
+ break;
}
}
+
+ if (!isKnownPrinter) {
+ PrinterHolder printerHolder = new PrinterHolder(printer);
+ printerHolder.removed = true;
+
+ mPrinterHolders.add(Math.max(0, getCount() - 3), printerHolder);
+ }
+
+ // Force reload to adjust selection in PrintersObserver.onChanged()
+ notifyDataSetChanged();
}
@Override
@@ -2428,8 +2465,7 @@
List<PrinterHolder> newPrinterHolders = new ArrayList<>();
// Update printers we already have which are either updated or removed.
- // We do not remove printers if the currently selected printer is removed
- // to prevent the user printing to a wrong printer.
+ // We do not remove the currently selected printer.
final int oldPrinterCount = mPrinterHolders.size();
for (int i = 0; i < oldPrinterCount; i++) {
PrinterHolder printerHolder = mPrinterHolders.get(i);
@@ -2438,10 +2474,11 @@
if (updatedPrinter != null) {
printerHolder.printer = updatedPrinter;
printerHolder.removed = false;
- } else {
+ newPrinterHolders.add(printerHolder);
+ } else if (mCurrentPrinter != null && mCurrentPrinter.getId().equals(oldPrinterId)){
printerHolder.removed = true;
+ newPrinterHolders.add(printerHolder);
}
- newPrinterHolders.add(printerHolder);
}
// Add the rest of the new printers, i.e. what is left.
@@ -2473,14 +2510,25 @@
return null;
}
- public void pruneRemovedPrinters() {
+ /**
+ * Remove a printer from the holders if it is marked as removed.
+ *
+ * @param printerId the id of the printer to remove.
+ *
+ * @return true iff the printer was removed.
+ */
+ public boolean pruneRemovedPrinter(PrinterId printerId) {
final int holderCounts = mPrinterHolders.size();
for (int i = holderCounts - 1; i >= 0; i--) {
PrinterHolder printerHolder = mPrinterHolders.get(i);
- if (printerHolder.removed) {
+
+ if (printerHolder.printer.getId().equals(printerId) && printerHolder.removed) {
mPrinterHolders.remove(i);
+ return true;
}
}
+
+ return false;
}
private void addPrinters(List<PrinterHolder> list, Collection<PrinterInfo> printers) {
@@ -2525,17 +2573,17 @@
PrinterHolder printerHolder = mDestinationSpinnerAdapter.getPrinterHolder(
oldPrinterState.getId());
- if (printerHolder == null) {
- return;
- }
PrinterInfo newPrinterState = printerHolder.printer;
- if (!printerHolder.removed) {
- mDestinationSpinnerAdapter.pruneRemovedPrinters();
- } else {
+ if (printerHolder.removed) {
onPrinterUnavailable(newPrinterState);
}
+ if (mDestinationSpinner.getSelectedItem() != printerHolder) {
+ mDestinationSpinner.setSelection(
+ mDestinationSpinnerAdapter.getPrinterIndex(newPrinterState.getId()));
+ }
+
if (oldPrinterState.equals(newPrinterState)) {
return;
}
@@ -2607,6 +2655,8 @@
private final class MyOnItemSelectedListener implements AdapterView.OnItemSelectedListener {
@Override
public void onItemSelected(AdapterView<?> spinner, View view, int position, long id) {
+ boolean clearRanges = false;
+
if (spinner == mDestinationSpinner) {
if (position == AdapterView.INVALID_POSITION) {
return;
@@ -2625,13 +2675,28 @@
return;
}
+ PrinterId oldId = null;
+ if (mCurrentPrinter != null) {
+ oldId = mCurrentPrinter.getId();
+ }
+
mCurrentPrinter = currentPrinter;
+ if (oldId != null) {
+ boolean printerRemoved = mDestinationSpinnerAdapter.pruneRemovedPrinter(oldId);
+
+ if (printerRemoved) {
+ // Trigger PrinterObserver.onChanged to adjust selection. This will call
+ // this function again.
+ mDestinationSpinnerAdapter.notifyDataSetChanged();
+ return;
+ }
+ }
+
PrinterHolder printerHolder = mDestinationSpinnerAdapter.getPrinterHolder(
currentPrinter.getId());
if (!printerHolder.removed) {
setState(STATE_CONFIGURING);
- mDestinationSpinnerAdapter.pruneRemovedPrinters();
ensurePreviewUiShown();
}
@@ -2653,10 +2718,17 @@
} else if (spinner == mMediaSizeSpinner) {
SpinnerItem<MediaSize> mediaItem = mMediaSizeSpinnerAdapter.getItem(position);
PrintAttributes attributes = mPrintJob.getAttributes();
+
+ MediaSize newMediaSize;
if (mOrientationSpinner.getSelectedItemPosition() == 0) {
- attributes.setMediaSize(mediaItem.value.asPortrait());
+ newMediaSize = mediaItem.value.asPortrait();
} else {
- attributes.setMediaSize(mediaItem.value.asLandscape());
+ newMediaSize = mediaItem.value.asLandscape();
+ }
+
+ if (newMediaSize != attributes.getMediaSize()) {
+ clearRanges = true;
+ attributes.setMediaSize(newMediaSize);
}
} else if (spinner == mColorModeSpinner) {
SpinnerItem<Integer> colorModeItem = mColorModeSpinnerAdapter.getItem(position);
@@ -2668,25 +2740,35 @@
SpinnerItem<Integer> orientationItem = mOrientationSpinnerAdapter.getItem(position);
PrintAttributes attributes = mPrintJob.getAttributes();
if (mMediaSizeSpinner.getSelectedItem() != null) {
- if (orientationItem.value == ORIENTATION_PORTRAIT) {
- attributes.copyFrom(attributes.asPortrait());
- } else {
- attributes.copyFrom(attributes.asLandscape());
+ boolean isPortrait = attributes.isPortrait();
+
+ if (isPortrait != (orientationItem.value == ORIENTATION_PORTRAIT)) {
+ clearRanges = true;
+ if (orientationItem.value == ORIENTATION_PORTRAIT) {
+ attributes.copyFrom(attributes.asPortrait());
+ } else {
+ attributes.copyFrom(attributes.asLandscape());
+ }
}
}
} else if (spinner == mRangeOptionsSpinner) {
if (mRangeOptionsSpinner.getSelectedItemPosition() == 0) {
+ clearRanges = true;
mPageRangeEditText.setText("");
} else if (TextUtils.isEmpty(mPageRangeEditText.getText())) {
mPageRangeEditText.setError("");
}
}
- if (canUpdateDocument()) {
- updateDocument(false);
+ if (clearRanges) {
+ clearPageRanges();
}
updateOptionsUi();
+
+ if (canUpdateDocument()) {
+ updateDocument(false);
+ }
}
@Override
@@ -2702,6 +2784,10 @@
if (!TextUtils.isEmpty(editText.getText())) {
editText.setSelection(editText.getText().length());
}
+
+ if (view == mPageRangeEditText && !hasFocus) {
+ updateSelectedPagesFromTextField();
+ }
}
}
@@ -2719,19 +2805,22 @@
@Override
public void afterTextChanged(Editable editable) {
final boolean hadErrors = hasErrors();
-
String text = editable.toString();
if (TextUtils.isEmpty(text)) {
- mPageRangeEditText.setError("");
- updateOptionsUi();
+ if (mPageRangeEditText.getError() == null) {
+ mPageRangeEditText.setError("");
+ updateOptionsUi();
+ }
return;
}
String escapedText = PATTERN_ESCAPE_SPECIAL_CHARS.matcher(text).replaceAll("////");
if (!PATTERN_PAGE_RANGE.matcher(escapedText).matches()) {
- mPageRangeEditText.setError("");
- updateOptionsUi();
+ if (mPageRangeEditText.getError() == null) {
+ mPageRangeEditText.setError("");
+ updateOptionsUi();
+ }
return;
}
@@ -2747,8 +2836,10 @@
}
final int pageIndex = Integer.parseInt(numericString);
if (pageIndex < 1 || pageIndex > pageCount) {
- mPageRangeEditText.setError("");
- updateOptionsUi();
+ if (mPageRangeEditText.getError() == null) {
+ mPageRangeEditText.setError("");
+ updateOptionsUi();
+ }
return;
}
}
@@ -2757,13 +2848,14 @@
// greater than the to page. When computing the requested pages
// we just swap them if necessary.
- mPageRangeEditText.setError(null);
- mPrintButton.setEnabled(true);
- updateOptionsUi();
-
- if (hadErrors && !hasErrors()) {
+ if (mPageRangeEditText.getError() != null) {
+ mPageRangeEditText.setError(null);
updateOptionsUi();
}
+
+ if (hadErrors && canUpdateDocument()) {
+ updateDocument(false);
+ }
}
}
@@ -2783,8 +2875,10 @@
final boolean hadErrors = hasErrors();
if (editable.length() == 0) {
- mCopiesEditText.setError("");
- updateOptionsUi();
+ if (mCopiesEditText.getError() == null) {
+ mCopiesEditText.setError("");
+ updateOptionsUi();
+ }
return;
}
@@ -2796,16 +2890,19 @@
}
if (copies < MIN_COPIES) {
- mCopiesEditText.setError("");
- updateOptionsUi();
+ if (mCopiesEditText.getError() == null) {
+ mCopiesEditText.setError("");
+ updateOptionsUi();
+ }
return;
}
mPrintJob.setCopies(copies);
- mCopiesEditText.setError(null);
-
- updateOptionsUi();
+ if (mCopiesEditText.getError() != null) {
+ mCopiesEditText.setError(null);
+ updateOptionsUi();
+ }
if (hadErrors && canUpdateDocument()) {
updateDocument(false);
@@ -2820,29 +2917,50 @@
private boolean mPosted;
+ /** State before run was executed */
+ private int mPreviousState = -1;
+
public ProgressMessageController(Context context) {
mHandler = new Handler(context.getMainLooper(), null, false);
}
public void post() {
- if (mPosted) {
+ if (mState == STATE_UPDATE_SLOW) {
+ setState(STATE_UPDATE_SLOW);
+ ensureProgressUiShown();
+ updateOptionsUi();
+
+ return;
+ } else if (mPosted) {
return;
}
+ mPreviousState = -1;
mPosted = true;
mHandler.postDelayed(this, PROGRESS_TIMEOUT_MILLIS);
}
- public void cancel() {
+ private int getStateAfterCancel() {
+ if (mPreviousState == -1) {
+ return mState;
+ } else {
+ return mPreviousState;
+ }
+ }
+
+ public int cancel() {
if (!mPosted) {
- return;
+ return getStateAfterCancel();
}
mPosted = false;
mHandler.removeCallbacks(this);
+
+ return getStateAfterCancel();
}
@Override
public void run() {
mPosted = false;
+ mPreviousState = mState;
setState(STATE_UPDATE_SLOW);
ensureProgressUiShown();
updateOptionsUi();
@@ -2991,12 +3109,10 @@
List<PageRange> rangesToShred = new ArrayList<>();
PageRange previousRange = null;
- final int pageCount = printJob.getDocumentInfo().getPageCount();
-
PageRange[] printedPages = printJob.getPages();
final int rangeCount = printedPages.length;
for (int i = 0; i < rangeCount; i++) {
- PageRange range = PageRangeUtils.asAbsoluteRange(printedPages[i], pageCount);
+ PageRange range = printedPages[i];
if (previousRange == null) {
final int startPageIdx = 0;
@@ -3015,11 +3131,8 @@
}
if (i == rangeCount - 1) {
- final int startPageIdx = range.getEnd() + 1;
- final int endPageIdx = printJob.getDocumentInfo().getPageCount() - 1;
- if (startPageIdx <= endPageIdx) {
- PageRange removedRange = new PageRange(startPageIdx, endPageIdx);
- rangesToShred.add(removedRange);
+ if (range.getEnd() != Integer.MAX_VALUE) {
+ rangesToShred.add(new PageRange(range.getEnd() + 1, Integer.MAX_VALUE));
}
}
diff --git a/packages/PrintSpooler/src/com/android/printspooler/ui/SelectPrinterActivity.java b/packages/PrintSpooler/src/com/android/printspooler/ui/SelectPrinterActivity.java
index e53a522..cee16c8 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/ui/SelectPrinterActivity.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/ui/SelectPrinterActivity.java
@@ -73,8 +73,9 @@
private static final int LOADER_ID_PRINT_REGISTRY_INT = 2;
private static final int LOADER_ID_ENABLED_PRINT_SERVICES = 3;
- public static final String INTENT_EXTRA_PRINTER_ID = "INTENT_EXTRA_PRINTER_ID";
+ public static final String INTENT_EXTRA_PRINTER = "INTENT_EXTRA_PRINTER";
+ private static final String EXTRA_PRINTER = "EXTRA_PRINTER";
private static final String EXTRA_PRINTER_ID = "EXTRA_PRINTER_ID";
private static final String KEY_NOT_FIRST_CREATE = "KEY_NOT_FIRST_CREATE";
@@ -134,7 +135,7 @@
if (printer == null) {
startAddPrinterActivity();
} else {
- onPrinterSelected(printer.getId());
+ onPrinterSelected(printer);
}
}
});
@@ -244,7 +245,7 @@
MenuItem selectItem = menu.add(Menu.NONE, R.string.print_select_printer,
Menu.NONE, R.string.print_select_printer);
Intent intent = new Intent();
- intent.putExtra(EXTRA_PRINTER_ID, printer.getId());
+ intent.putExtra(EXTRA_PRINTER, printer);
selectItem.setIntent(intent);
}
@@ -263,8 +264,8 @@
public boolean onContextItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.string.print_select_printer: {
- PrinterId printerId = item.getIntent().getParcelableExtra(EXTRA_PRINTER_ID);
- onPrinterSelected(printerId);
+ PrinterInfo printer = item.getIntent().getParcelableExtra(EXTRA_PRINTER);
+ onPrinterSelected(printer);
} return true;
case R.string.print_forget_printer: {
@@ -302,9 +303,9 @@
super.onStop();
}
- private void onPrinterSelected(PrinterId printerId) {
+ private void onPrinterSelected(PrinterInfo printer) {
Intent intent = new Intent();
- intent.putExtra(INTENT_EXTRA_PRINTER_ID, printerId);
+ intent.putExtra(INTENT_EXTRA_PRINTER, printer);
setResult(RESULT_OK, intent);
finish();
}
diff --git a/packages/SettingsLib/res/values-af/strings.xml b/packages/SettingsLib/res/values-af/strings.xml
index 406c9b7..9cf9dc9 100644
--- a/packages/SettingsLib/res/values-af/strings.xml
+++ b/packages/SettingsLib/res/values-af/strings.xml
@@ -278,8 +278,7 @@
<string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"Laat loop WebView-leweraars in \'n geïsoleerde proses."</string>
<string name="select_webview_provider_title" msgid="4628592979751918907">"WebView-implementering"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Stel WebView-implementering"</string>
- <!-- no translation found for select_webview_provider_toast_text (5466970498308266359) -->
- <skip />
+ <string name="select_webview_provider_toast_text" msgid="5466970498308266359">"Hierdie keuse is nie meer geldig nie. Probeer weer."</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"Skakel om na lêerenkripsie"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Skakel om …"</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Lêerenkripsie is reeds uitgevoer"</string>
@@ -317,4 +316,10 @@
<string name="home" msgid="8263346537524314127">"Tuis"</string>
<string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> gelede"</string>
<string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> oor"</string>
+ <string name="screen_zoom_summary_small" msgid="5867245310241621570">"Klein"</string>
+ <string name="screen_zoom_summary_default" msgid="2247006805614056507">"Verstek"</string>
+ <string name="screen_zoom_summary_large" msgid="4835294730065424084">"Groot"</string>
+ <string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"Groter"</string>
+ <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Grootste"</string>
+ <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Gepasmaak (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-am/strings.xml b/packages/SettingsLib/res/values-am/strings.xml
index e4cd8b9..40e5a31 100644
--- a/packages/SettingsLib/res/values-am/strings.xml
+++ b/packages/SettingsLib/res/values-am/strings.xml
@@ -278,8 +278,7 @@
<string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"የWebView ምስል ሰሪዎችን በተገለለ ሂደት ውስጥ አሂድ።"</string>
<string name="select_webview_provider_title" msgid="4628592979751918907">"የWebView ትግበራ"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"የWebView ትግበራን ያዘጋጁ"</string>
- <!-- no translation found for select_webview_provider_toast_text (5466970498308266359) -->
- <skip />
+ <string name="select_webview_provider_toast_text" msgid="5466970498308266359">"ይህ ምርጫ ከአሁን በኋላ የሚሰራ አይደለም። እንደገና ይሞክሩ።"</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"ወደ ፋይል ምሥጠራ ቀይር"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"ለውጥ…"</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"ፋይል አስቀድሞ ተመስጥሯል"</string>
@@ -317,4 +316,10 @@
<string name="home" msgid="8263346537524314127">"መነሻ"</string>
<string name="charge_length_format" msgid="8978516217024434156">"ከ<xliff:g id="ID_1">%1$s</xliff:g> በፊት"</string>
<string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> ቀርቷል"</string>
+ <string name="screen_zoom_summary_small" msgid="5867245310241621570">"ትንሽ"</string>
+ <string name="screen_zoom_summary_default" msgid="2247006805614056507">"ነባሪ"</string>
+ <string name="screen_zoom_summary_large" msgid="4835294730065424084">"ትልቅ"</string>
+ <string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"ተለቅ ያለ"</string>
+ <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"በጣም ተለቅ ያለ"</string>
+ <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"ብጁ (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-ar/strings.xml b/packages/SettingsLib/res/values-ar/strings.xml
index ad87a89..e21b02c 100644
--- a/packages/SettingsLib/res/values-ar/strings.xml
+++ b/packages/SettingsLib/res/values-ar/strings.xml
@@ -316,4 +316,10 @@
<string name="home" msgid="8263346537524314127">"الشاشة الرئيسية"</string>
<string name="charge_length_format" msgid="8978516217024434156">"قبل <xliff:g id="ID_1">%1$s</xliff:g>"</string>
<string name="remaining_length_format" msgid="7886337596669190587">"يتبقى <xliff:g id="ID_1">%1$s</xliff:g>"</string>
+ <string name="screen_zoom_summary_small" msgid="5867245310241621570">"صغير"</string>
+ <string name="screen_zoom_summary_default" msgid="2247006805614056507">"افتراضي"</string>
+ <string name="screen_zoom_summary_large" msgid="4835294730065424084">"كبير"</string>
+ <string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"أكبر"</string>
+ <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"أكبر مستوى"</string>
+ <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"مخصص (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-az-rAZ/strings.xml b/packages/SettingsLib/res/values-az-rAZ/strings.xml
index c141445..ca06e664 100644
--- a/packages/SettingsLib/res/values-az-rAZ/strings.xml
+++ b/packages/SettingsLib/res/values-az-rAZ/strings.xml
@@ -278,8 +278,7 @@
<string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"WebView rendererləri təcrid olunmuş prosesdə işlədin."</string>
<string name="select_webview_provider_title" msgid="4628592979751918907">"WebView icrası"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"WebView icrasını ayarlayın"</string>
- <!-- no translation found for select_webview_provider_toast_text (5466970498308266359) -->
- <skip />
+ <string name="select_webview_provider_toast_text" msgid="5466970498308266359">"Bu seçim artıq etibarlı deyil. Yenidən cəhd edin."</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"Fayl şifrələnməsinə çevirin"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Çevirin..."</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Fayl artıq şifrələnib"</string>
@@ -317,4 +316,10 @@
<string name="home" msgid="8263346537524314127">"Əsas səhifə"</string>
<string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> əvvəl"</string>
<string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> qalıb"</string>
+ <string name="screen_zoom_summary_small" msgid="5867245310241621570">"Kiçik"</string>
+ <string name="screen_zoom_summary_default" msgid="2247006805614056507">"Defolt"</string>
+ <string name="screen_zoom_summary_large" msgid="4835294730065424084">"Böyük"</string>
+ <string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"Daha böyük"</string>
+ <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Ən böyük"</string>
+ <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Fərdi (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
index 3e3cce0..4bd9b03 100644
--- a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
+++ b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
@@ -316,4 +316,10 @@
<string name="home" msgid="8263346537524314127">"Početni"</string>
<string name="charge_length_format" msgid="8978516217024434156">"Pre <xliff:g id="ID_1">%1$s</xliff:g>"</string>
<string name="remaining_length_format" msgid="7886337596669190587">"Još <xliff:g id="ID_1">%1$s</xliff:g>"</string>
+ <string name="screen_zoom_summary_small" msgid="5867245310241621570">"Mali"</string>
+ <string name="screen_zoom_summary_default" msgid="2247006805614056507">"Podrazumevano"</string>
+ <string name="screen_zoom_summary_large" msgid="4835294730065424084">"Veliki"</string>
+ <string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"Veći"</string>
+ <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Najveći"</string>
+ <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Prilagođeni (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-be-rBY/strings.xml b/packages/SettingsLib/res/values-be-rBY/strings.xml
index 08aa3a0..a70fc69 100644
--- a/packages/SettingsLib/res/values-be-rBY/strings.xml
+++ b/packages/SettingsLib/res/values-be-rBY/strings.xml
@@ -278,8 +278,7 @@
<string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"Запусціць апрацоўшчыкі WebView у ізаляваным працэсе."</string>
<string name="select_webview_provider_title" msgid="4628592979751918907">"Рэалізацыя WebView"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Наладзіць рэалізацыю WebView"</string>
- <!-- no translation found for select_webview_provider_toast_text (5466970498308266359) -->
- <skip />
+ <string name="select_webview_provider_toast_text" msgid="5466970498308266359">"Гэты варыянт больш не даступны. Паспрабуйце яшчэ раз."</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"Перайсці на шыфраванне файлаў"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Пераход..."</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Шыфраванне файлаў ужо дзейнічае"</string>
@@ -317,4 +316,10 @@
<string name="home" msgid="8263346537524314127">"Галоўная"</string>
<string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> таму назад"</string>
<string name="remaining_length_format" msgid="7886337596669190587">"Засталося <xliff:g id="ID_1">%1$s</xliff:g>"</string>
+ <string name="screen_zoom_summary_small" msgid="5867245310241621570">"Маленькі"</string>
+ <string name="screen_zoom_summary_default" msgid="2247006805614056507">"Стандартны"</string>
+ <string name="screen_zoom_summary_large" msgid="4835294730065424084">"Вялікі"</string>
+ <string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"Большы"</string>
+ <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Найвялікшы"</string>
+ <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Карыстальніцкі (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-bg/strings.xml b/packages/SettingsLib/res/values-bg/strings.xml
index 2dbeeac..e0641b1 100644
--- a/packages/SettingsLib/res/values-bg/strings.xml
+++ b/packages/SettingsLib/res/values-bg/strings.xml
@@ -316,4 +316,10 @@
<string name="home" msgid="8263346537524314127">"Начало"</string>
<string name="charge_length_format" msgid="8978516217024434156">"Преди <xliff:g id="ID_1">%1$s</xliff:g>"</string>
<string name="remaining_length_format" msgid="7886337596669190587">"Оставащо време: <xliff:g id="ID_1">%1$s</xliff:g>"</string>
+ <string name="screen_zoom_summary_small" msgid="5867245310241621570">"Малко"</string>
+ <string name="screen_zoom_summary_default" msgid="2247006805614056507">"По подразбиране"</string>
+ <string name="screen_zoom_summary_large" msgid="4835294730065424084">"Голямо"</string>
+ <string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"По-голямо"</string>
+ <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Най-голямо"</string>
+ <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Персонализирано (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-bn-rBD/strings.xml b/packages/SettingsLib/res/values-bn-rBD/strings.xml
index eea4f06..5ca7d03 100644
--- a/packages/SettingsLib/res/values-bn-rBD/strings.xml
+++ b/packages/SettingsLib/res/values-bn-rBD/strings.xml
@@ -316,4 +316,10 @@
<string name="home" msgid="8263346537524314127">"হোম"</string>
<string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> আগে"</string>
<string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> বাকী আছে"</string>
+ <string name="screen_zoom_summary_small" msgid="5867245310241621570">"ক্ষুদ্র"</string>
+ <string name="screen_zoom_summary_default" msgid="2247006805614056507">"ডিফল্ট"</string>
+ <string name="screen_zoom_summary_large" msgid="4835294730065424084">"বড়"</string>
+ <string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"খুব বড়"</string>
+ <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"বৃহত্তম"</string>
+ <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"কাস্টম (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-bs-rBA/strings.xml b/packages/SettingsLib/res/values-bs-rBA/strings.xml
index cf9e4a4..ce0f409 100644
--- a/packages/SettingsLib/res/values-bs-rBA/strings.xml
+++ b/packages/SettingsLib/res/values-bs-rBA/strings.xml
@@ -278,8 +278,7 @@
<string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"Pokrenite WebView operatera u izolovanom procesu."</string>
<string name="select_webview_provider_title" msgid="4628592979751918907">"Postavljanje WebViewa"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Podesi WebView"</string>
- <!-- no translation found for select_webview_provider_toast_text (5466970498308266359) -->
- <skip />
+ <string name="select_webview_provider_toast_text" msgid="5466970498308266359">"Ovaj izbor više ne vrijedi. Pokušajte ponovo."</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"Pretvori u šifrirani fajl"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Pretvaranje…"</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Fajl je već šifriran"</string>
@@ -317,4 +316,10 @@
<string name="home" msgid="8263346537524314127">"Početna stranica"</string>
<string name="charge_length_format" msgid="8978516217024434156">"prije <xliff:g id="ID_1">%1$s</xliff:g>"</string>
<string name="remaining_length_format" msgid="7886337596669190587">"Još otprilike <xliff:g id="ID_1">%1$s</xliff:g>"</string>
+ <string name="screen_zoom_summary_small" msgid="5867245310241621570">"Malo"</string>
+ <string name="screen_zoom_summary_default" msgid="2247006805614056507">"Zadano"</string>
+ <string name="screen_zoom_summary_large" msgid="4835294730065424084">"Veliko"</string>
+ <string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"Veće"</string>
+ <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Najveće"</string>
+ <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Prilagodi (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-ca/strings.xml b/packages/SettingsLib/res/values-ca/strings.xml
index 8d158ac..5106f5b 100644
--- a/packages/SettingsLib/res/values-ca/strings.xml
+++ b/packages/SettingsLib/res/values-ca/strings.xml
@@ -316,4 +316,10 @@
<string name="home" msgid="8263346537524314127">"Inici"</string>
<string name="charge_length_format" msgid="8978516217024434156">"Fa <xliff:g id="ID_1">%1$s</xliff:g>"</string>
<string name="remaining_length_format" msgid="7886337596669190587">"Temps restant: <xliff:g id="ID_1">%1$s</xliff:g>"</string>
+ <string name="screen_zoom_summary_small" msgid="5867245310241621570">"Petit"</string>
+ <string name="screen_zoom_summary_default" msgid="2247006805614056507">"Predeterminat"</string>
+ <string name="screen_zoom_summary_large" msgid="4835294730065424084">"Gran"</string>
+ <string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"Més gran"</string>
+ <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Màxim"</string>
+ <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Personalitzat (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-cs/strings.xml b/packages/SettingsLib/res/values-cs/strings.xml
index 9e9abad..3d3dd6f 100644
--- a/packages/SettingsLib/res/values-cs/strings.xml
+++ b/packages/SettingsLib/res/values-cs/strings.xml
@@ -316,4 +316,10 @@
<string name="home" msgid="8263346537524314127">"Plocha"</string>
<string name="charge_length_format" msgid="8978516217024434156">"před <xliff:g id="ID_1">%1$s</xliff:g>"</string>
<string name="remaining_length_format" msgid="7886337596669190587">"Zbývající čas: <xliff:g id="ID_1">%1$s</xliff:g>"</string>
+ <string name="screen_zoom_summary_small" msgid="5867245310241621570">"Malé"</string>
+ <string name="screen_zoom_summary_default" msgid="2247006805614056507">"Výchozí"</string>
+ <string name="screen_zoom_summary_large" msgid="4835294730065424084">"Velké"</string>
+ <string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"Větší"</string>
+ <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Největší"</string>
+ <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Vlastní (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-da/strings.xml b/packages/SettingsLib/res/values-da/strings.xml
index 659bd32..1f354b7 100644
--- a/packages/SettingsLib/res/values-da/strings.xml
+++ b/packages/SettingsLib/res/values-da/strings.xml
@@ -316,4 +316,10 @@
<string name="home" msgid="8263346537524314127">"Start"</string>
<string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> siden"</string>
<string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> tilbage"</string>
+ <string name="screen_zoom_summary_small" msgid="5867245310241621570">"Lille"</string>
+ <string name="screen_zoom_summary_default" msgid="2247006805614056507">"Standard"</string>
+ <string name="screen_zoom_summary_large" msgid="4835294730065424084">"Stor"</string>
+ <string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"Større"</string>
+ <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Størst"</string>
+ <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Tilpasset (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-de/strings.xml b/packages/SettingsLib/res/values-de/strings.xml
index 67d0198..404b72b 100644
--- a/packages/SettingsLib/res/values-de/strings.xml
+++ b/packages/SettingsLib/res/values-de/strings.xml
@@ -316,4 +316,10 @@
<string name="home" msgid="8263346537524314127">"Startseite"</string>
<string name="charge_length_format" msgid="8978516217024434156">"Vor <xliff:g id="ID_1">%1$s</xliff:g>"</string>
<string name="remaining_length_format" msgid="7886337596669190587">"Noch <xliff:g id="ID_1">%1$s</xliff:g> verbleibend"</string>
+ <string name="screen_zoom_summary_small" msgid="5867245310241621570">"Klein"</string>
+ <string name="screen_zoom_summary_default" msgid="2247006805614056507">"Standard"</string>
+ <string name="screen_zoom_summary_large" msgid="4835294730065424084">"Groß"</string>
+ <string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"Größer"</string>
+ <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Am größten"</string>
+ <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Benutzerdefiniert (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-el/strings.xml b/packages/SettingsLib/res/values-el/strings.xml
index 263703c..52988f6 100644
--- a/packages/SettingsLib/res/values-el/strings.xml
+++ b/packages/SettingsLib/res/values-el/strings.xml
@@ -316,4 +316,10 @@
<string name="home" msgid="8263346537524314127">"Αρχική οθόνη"</string>
<string name="charge_length_format" msgid="8978516217024434156">"Πριν από <xliff:g id="ID_1">%1$s</xliff:g>"</string>
<string name="remaining_length_format" msgid="7886337596669190587">"Απομένουν <xliff:g id="ID_1">%1$s</xliff:g>"</string>
+ <string name="screen_zoom_summary_small" msgid="5867245310241621570">"Μικρά"</string>
+ <string name="screen_zoom_summary_default" msgid="2247006805614056507">"Προεπιλογή"</string>
+ <string name="screen_zoom_summary_large" msgid="4835294730065424084">"Μεγάλα"</string>
+ <string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"Πιο μεγάλα"</string>
+ <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Μεγαλύτερα"</string>
+ <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Προσαρμοσμένη (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-en-rAU/strings.xml b/packages/SettingsLib/res/values-en-rAU/strings.xml
index 7a00eb7..b2df062 100644
--- a/packages/SettingsLib/res/values-en-rAU/strings.xml
+++ b/packages/SettingsLib/res/values-en-rAU/strings.xml
@@ -316,4 +316,10 @@
<string name="home" msgid="8263346537524314127">"Home"</string>
<string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> ago"</string>
<string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> left"</string>
+ <string name="screen_zoom_summary_small" msgid="5867245310241621570">"Small"</string>
+ <string name="screen_zoom_summary_default" msgid="2247006805614056507">"Default"</string>
+ <string name="screen_zoom_summary_large" msgid="4835294730065424084">"Large"</string>
+ <string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"Larger"</string>
+ <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Largest"</string>
+ <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Custom (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-en-rGB/strings.xml b/packages/SettingsLib/res/values-en-rGB/strings.xml
index 7a00eb7..b2df062 100644
--- a/packages/SettingsLib/res/values-en-rGB/strings.xml
+++ b/packages/SettingsLib/res/values-en-rGB/strings.xml
@@ -316,4 +316,10 @@
<string name="home" msgid="8263346537524314127">"Home"</string>
<string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> ago"</string>
<string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> left"</string>
+ <string name="screen_zoom_summary_small" msgid="5867245310241621570">"Small"</string>
+ <string name="screen_zoom_summary_default" msgid="2247006805614056507">"Default"</string>
+ <string name="screen_zoom_summary_large" msgid="4835294730065424084">"Large"</string>
+ <string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"Larger"</string>
+ <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Largest"</string>
+ <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Custom (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-en-rIN/strings.xml b/packages/SettingsLib/res/values-en-rIN/strings.xml
index 7a00eb7..b2df062 100644
--- a/packages/SettingsLib/res/values-en-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-en-rIN/strings.xml
@@ -316,4 +316,10 @@
<string name="home" msgid="8263346537524314127">"Home"</string>
<string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> ago"</string>
<string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> left"</string>
+ <string name="screen_zoom_summary_small" msgid="5867245310241621570">"Small"</string>
+ <string name="screen_zoom_summary_default" msgid="2247006805614056507">"Default"</string>
+ <string name="screen_zoom_summary_large" msgid="4835294730065424084">"Large"</string>
+ <string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"Larger"</string>
+ <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Largest"</string>
+ <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Custom (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-es-rUS/strings.xml b/packages/SettingsLib/res/values-es-rUS/strings.xml
index b45753d..dd7ee4d 100644
--- a/packages/SettingsLib/res/values-es-rUS/strings.xml
+++ b/packages/SettingsLib/res/values-es-rUS/strings.xml
@@ -316,4 +316,10 @@
<string name="home" msgid="8263346537524314127">"Página principal"</string>
<string name="charge_length_format" msgid="8978516217024434156">"Hace <xliff:g id="ID_1">%1$s</xliff:g>"</string>
<string name="remaining_length_format" msgid="7886337596669190587">"Falta <xliff:g id="ID_1">%1$s</xliff:g>"</string>
+ <string name="screen_zoom_summary_small" msgid="5867245310241621570">"Pequeño"</string>
+ <string name="screen_zoom_summary_default" msgid="2247006805614056507">"Predeterminado"</string>
+ <string name="screen_zoom_summary_large" msgid="4835294730065424084">"Grande"</string>
+ <string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"Más grande"</string>
+ <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Máximo"</string>
+ <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Personalizado (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-es/strings.xml b/packages/SettingsLib/res/values-es/strings.xml
index 1e36088..0cc6cb6 100644
--- a/packages/SettingsLib/res/values-es/strings.xml
+++ b/packages/SettingsLib/res/values-es/strings.xml
@@ -316,4 +316,10 @@
<string name="home" msgid="8263346537524314127">"Inicio"</string>
<string name="charge_length_format" msgid="8978516217024434156">"Hace <xliff:g id="ID_1">%1$s</xliff:g>"</string>
<string name="remaining_length_format" msgid="7886337596669190587">"Tiempo restante: <xliff:g id="ID_1">%1$s</xliff:g>"</string>
+ <string name="screen_zoom_summary_small" msgid="5867245310241621570">"Pequeño"</string>
+ <string name="screen_zoom_summary_default" msgid="2247006805614056507">"Predeterminado"</string>
+ <string name="screen_zoom_summary_large" msgid="4835294730065424084">"Grande"</string>
+ <string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"Más grande"</string>
+ <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Lo más grande posible"</string>
+ <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Personalizado (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-et-rEE/strings.xml b/packages/SettingsLib/res/values-et-rEE/strings.xml
index cb0e7f2..a275b1a 100644
--- a/packages/SettingsLib/res/values-et-rEE/strings.xml
+++ b/packages/SettingsLib/res/values-et-rEE/strings.xml
@@ -316,4 +316,10 @@
<string name="home" msgid="8263346537524314127">"Avaekraan"</string>
<string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> tagasi"</string>
<string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> on jäänud"</string>
+ <string name="screen_zoom_summary_small" msgid="5867245310241621570">"Väike"</string>
+ <string name="screen_zoom_summary_default" msgid="2247006805614056507">"Vaikimisi"</string>
+ <string name="screen_zoom_summary_large" msgid="4835294730065424084">"Suur"</string>
+ <string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"Suurem"</string>
+ <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Suurim"</string>
+ <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Kohandatud (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-eu-rES/strings.xml b/packages/SettingsLib/res/values-eu-rES/strings.xml
index f09949f..2556224 100644
--- a/packages/SettingsLib/res/values-eu-rES/strings.xml
+++ b/packages/SettingsLib/res/values-eu-rES/strings.xml
@@ -316,4 +316,10 @@
<string name="home" msgid="8263346537524314127">"Hasierako pantaila"</string>
<string name="charge_length_format" msgid="8978516217024434156">"Duela <xliff:g id="ID_1">%1$s</xliff:g>"</string>
<string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> guztiz kargatu arte"</string>
+ <string name="screen_zoom_summary_small" msgid="5867245310241621570">"Txikia"</string>
+ <string name="screen_zoom_summary_default" msgid="2247006805614056507">"Lehenetsia"</string>
+ <string name="screen_zoom_summary_large" msgid="4835294730065424084">"Handia"</string>
+ <string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"Oso handia"</string>
+ <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Handiena"</string>
+ <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Pertsonalizatua (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-fa/strings.xml b/packages/SettingsLib/res/values-fa/strings.xml
index c621be3..1e67182 100644
--- a/packages/SettingsLib/res/values-fa/strings.xml
+++ b/packages/SettingsLib/res/values-fa/strings.xml
@@ -278,8 +278,7 @@
<string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"اجرای تولیدکننده تصویر وبنما در یک پردازش مجزا."</string>
<string name="select_webview_provider_title" msgid="4628592979751918907">"اجرای وبنما"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"تنظیم اجرای وبنما"</string>
- <!-- no translation found for select_webview_provider_toast_text (5466970498308266359) -->
- <skip />
+ <string name="select_webview_provider_toast_text" msgid="5466970498308266359">"این انتخاب دیگر معتبر نیست. دوباره امتحان کنید."</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"تبدیل به رمزگذاری برحسب فایل"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"تبدیل…"</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"از قبل به رمزگذاری بر حسب فایل تبدیل شده است"</string>
@@ -317,4 +316,10 @@
<string name="home" msgid="8263346537524314127">"صفحه اصلی"</string>
<string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> قبل"</string>
<string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> باقی مانده است"</string>
+ <string name="screen_zoom_summary_small" msgid="5867245310241621570">"کوچک"</string>
+ <string name="screen_zoom_summary_default" msgid="2247006805614056507">"پیشفرض"</string>
+ <string name="screen_zoom_summary_large" msgid="4835294730065424084">"بزرگ"</string>
+ <string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"بزرگتر"</string>
+ <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"بزرگترین"</string>
+ <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"سفارشی (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-fi/strings.xml b/packages/SettingsLib/res/values-fi/strings.xml
index 8ec2f6e..3d8ac98 100644
--- a/packages/SettingsLib/res/values-fi/strings.xml
+++ b/packages/SettingsLib/res/values-fi/strings.xml
@@ -316,4 +316,10 @@
<string name="home" msgid="8263346537524314127">"Aloitusnäyttö"</string>
<string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> sitten"</string>
<string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> jäljellä"</string>
+ <string name="screen_zoom_summary_small" msgid="5867245310241621570">"Pieni"</string>
+ <string name="screen_zoom_summary_default" msgid="2247006805614056507">"Oletus"</string>
+ <string name="screen_zoom_summary_large" msgid="4835294730065424084">"Suuri"</string>
+ <string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"Suurempi"</string>
+ <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Suurin"</string>
+ <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Muokattu (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-fr-rCA/strings.xml b/packages/SettingsLib/res/values-fr-rCA/strings.xml
index e2de253..4eb3a427 100644
--- a/packages/SettingsLib/res/values-fr-rCA/strings.xml
+++ b/packages/SettingsLib/res/values-fr-rCA/strings.xml
@@ -316,4 +316,10 @@
<string name="home" msgid="8263346537524314127">"Accueil"</string>
<string name="charge_length_format" msgid="8978516217024434156">"Il y a <xliff:g id="ID_1">%1$s</xliff:g>"</string>
<string name="remaining_length_format" msgid="7886337596669190587">"Durée restante :<xliff:g id="ID_1">%1$s</xliff:g>"</string>
+ <string name="screen_zoom_summary_small" msgid="5867245310241621570">"Petite"</string>
+ <string name="screen_zoom_summary_default" msgid="2247006805614056507">"Par défaut"</string>
+ <string name="screen_zoom_summary_large" msgid="4835294730065424084">"Grande"</string>
+ <string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"Plus grande"</string>
+ <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"La plus grande"</string>
+ <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Personnalisée (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-fr/strings.xml b/packages/SettingsLib/res/values-fr/strings.xml
index e3dd87a..efb10ec 100644
--- a/packages/SettingsLib/res/values-fr/strings.xml
+++ b/packages/SettingsLib/res/values-fr/strings.xml
@@ -316,4 +316,10 @@
<string name="home" msgid="8263346537524314127">"Accueil"</string>
<string name="charge_length_format" msgid="8978516217024434156">"Il y a <xliff:g id="ID_1">%1$s</xliff:g>"</string>
<string name="remaining_length_format" msgid="7886337596669190587">"Il reste <xliff:g id="ID_1">%1$s</xliff:g>."</string>
+ <string name="screen_zoom_summary_small" msgid="5867245310241621570">"Petit"</string>
+ <string name="screen_zoom_summary_default" msgid="2247006805614056507">"Par défaut"</string>
+ <string name="screen_zoom_summary_large" msgid="4835294730065424084">"Grand"</string>
+ <string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"Plus grand"</string>
+ <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Le plus grand"</string>
+ <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Personnalisé (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-gl-rES/strings.xml b/packages/SettingsLib/res/values-gl-rES/strings.xml
index e75fee6..3d61e21 100644
--- a/packages/SettingsLib/res/values-gl-rES/strings.xml
+++ b/packages/SettingsLib/res/values-gl-rES/strings.xml
@@ -316,4 +316,10 @@
<string name="home" msgid="8263346537524314127">"Inicio"</string>
<string name="charge_length_format" msgid="8978516217024434156">"Hai <xliff:g id="ID_1">%1$s</xliff:g>"</string>
<string name="remaining_length_format" msgid="7886337596669190587">"Tempo restante: <xliff:g id="ID_1">%1$s</xliff:g>"</string>
+ <string name="screen_zoom_summary_small" msgid="5867245310241621570">"Pequeno"</string>
+ <string name="screen_zoom_summary_default" msgid="2247006805614056507">"Predeterminado"</string>
+ <string name="screen_zoom_summary_large" msgid="4835294730065424084">"Grande"</string>
+ <string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"Máis grande"</string>
+ <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"O máis grande"</string>
+ <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Personalizado (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-gu-rIN/strings.xml b/packages/SettingsLib/res/values-gu-rIN/strings.xml
index 38b6089..628b4be 100644
--- a/packages/SettingsLib/res/values-gu-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-gu-rIN/strings.xml
@@ -316,4 +316,10 @@
<string name="home" msgid="8263346537524314127">"હોમ"</string>
<string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> પહેલાં"</string>
<string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> બાકી"</string>
+ <string name="screen_zoom_summary_small" msgid="5867245310241621570">"નાનું"</string>
+ <string name="screen_zoom_summary_default" msgid="2247006805614056507">"ડિફોલ્ટ"</string>
+ <string name="screen_zoom_summary_large" msgid="4835294730065424084">"મોટું"</string>
+ <string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"વધુ મોટું"</string>
+ <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"સૌથી મોટું"</string>
+ <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"કસ્ટમ (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-hi/strings.xml b/packages/SettingsLib/res/values-hi/strings.xml
index dce538b..047c7db 100644
--- a/packages/SettingsLib/res/values-hi/strings.xml
+++ b/packages/SettingsLib/res/values-hi/strings.xml
@@ -316,4 +316,10 @@
<string name="home" msgid="8263346537524314127">"होम"</string>
<string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> पहले"</string>
<string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> शेष"</string>
+ <string name="screen_zoom_summary_small" msgid="5867245310241621570">"छोटा"</string>
+ <string name="screen_zoom_summary_default" msgid="2247006805614056507">"डिफ़ॉल्ट"</string>
+ <string name="screen_zoom_summary_large" msgid="4835294730065424084">"बड़ा"</string>
+ <string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"अधिक बड़ा"</string>
+ <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"सबसे बड़ा"</string>
+ <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"कस्टम (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-hr/strings.xml b/packages/SettingsLib/res/values-hr/strings.xml
index 7a2acd8..f5ad6d2 100644
--- a/packages/SettingsLib/res/values-hr/strings.xml
+++ b/packages/SettingsLib/res/values-hr/strings.xml
@@ -316,4 +316,10 @@
<string name="home" msgid="8263346537524314127">"Početni zaslon"</string>
<string name="charge_length_format" msgid="8978516217024434156">"Prije <xliff:g id="ID_1">%1$s</xliff:g>"</string>
<string name="remaining_length_format" msgid="7886337596669190587">"Još <xliff:g id="ID_1">%1$s</xliff:g>"</string>
+ <string name="screen_zoom_summary_small" msgid="5867245310241621570">"Malo"</string>
+ <string name="screen_zoom_summary_default" msgid="2247006805614056507">"Zadano"</string>
+ <string name="screen_zoom_summary_large" msgid="4835294730065424084">"Veliko"</string>
+ <string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"Veće"</string>
+ <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Najveće"</string>
+ <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Prilagođeno (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-hu/strings.xml b/packages/SettingsLib/res/values-hu/strings.xml
index 426cff4..7279c9c 100644
--- a/packages/SettingsLib/res/values-hu/strings.xml
+++ b/packages/SettingsLib/res/values-hu/strings.xml
@@ -316,4 +316,10 @@
<string name="home" msgid="8263346537524314127">"Főoldal"</string>
<string name="charge_length_format" msgid="8978516217024434156">"Ennyi ideje: <xliff:g id="ID_1">%1$s</xliff:g>"</string>
<string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> van hátra"</string>
+ <string name="screen_zoom_summary_small" msgid="5867245310241621570">"Kicsi"</string>
+ <string name="screen_zoom_summary_default" msgid="2247006805614056507">"Alapértelmezett"</string>
+ <string name="screen_zoom_summary_large" msgid="4835294730065424084">"Nagy"</string>
+ <string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"Nagyobb"</string>
+ <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Legnagyobb"</string>
+ <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Egyéni (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-hy-rAM/strings.xml b/packages/SettingsLib/res/values-hy-rAM/strings.xml
index 8c62221..23d83a2 100644
--- a/packages/SettingsLib/res/values-hy-rAM/strings.xml
+++ b/packages/SettingsLib/res/values-hy-rAM/strings.xml
@@ -278,8 +278,7 @@
<string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"Գործարկել WebView-ի մշակիչները առանձնացված գործընթացում:"</string>
<string name="select_webview_provider_title" msgid="4628592979751918907">"WebView-ի իրականացում"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Ընտրեք WebView-ի իրականացումը"</string>
- <!-- no translation found for select_webview_provider_toast_text (5466970498308266359) -->
- <skip />
+ <string name="select_webview_provider_toast_text" msgid="5466970498308266359">"Այս ընտրանքն այլևս վավեր չէ: Փորձեք նորից:"</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"Վերածել ֆայլային գաղտնագրման"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Փոխարկել…"</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Ֆայլային գաղտնագրումն արդեն կատարվել է"</string>
@@ -317,4 +316,10 @@
<string name="home" msgid="8263346537524314127">"Գլխավոր էջ"</string>
<string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> առաջ"</string>
<string name="remaining_length_format" msgid="7886337596669190587">"Մնացել է <xliff:g id="ID_1">%1$s</xliff:g>"</string>
+ <string name="screen_zoom_summary_small" msgid="5867245310241621570">"Փոքր"</string>
+ <string name="screen_zoom_summary_default" msgid="2247006805614056507">"Կանխադրված"</string>
+ <string name="screen_zoom_summary_large" msgid="4835294730065424084">"Մեծ"</string>
+ <string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"Ավելի մեծ"</string>
+ <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Ամենամեծ"</string>
+ <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Հատուկ (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-in/strings.xml b/packages/SettingsLib/res/values-in/strings.xml
index 662bb22..24fd0f1 100644
--- a/packages/SettingsLib/res/values-in/strings.xml
+++ b/packages/SettingsLib/res/values-in/strings.xml
@@ -316,4 +316,10 @@
<string name="home" msgid="8263346537524314127">"Layar Utama"</string>
<string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> lalu"</string>
<string name="remaining_length_format" msgid="7886337596669190587">"Tersisa <xliff:g id="ID_1">%1$s</xliff:g>"</string>
+ <string name="screen_zoom_summary_small" msgid="5867245310241621570">"Kecil"</string>
+ <string name="screen_zoom_summary_default" msgid="2247006805614056507">"Default"</string>
+ <string name="screen_zoom_summary_large" msgid="4835294730065424084">"Besar"</string>
+ <string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"Lebih besar"</string>
+ <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Terbesar"</string>
+ <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"(<xliff:g id="DENSITYDPI">%d</xliff:g>) khusus"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-is-rIS/strings.xml b/packages/SettingsLib/res/values-is-rIS/strings.xml
index 30440da..e22dbe0 100644
--- a/packages/SettingsLib/res/values-is-rIS/strings.xml
+++ b/packages/SettingsLib/res/values-is-rIS/strings.xml
@@ -316,4 +316,10 @@
<string name="home" msgid="8263346537524314127">"Heim"</string>
<string name="charge_length_format" msgid="8978516217024434156">"Fyrir <xliff:g id="ID_1">%1$s</xliff:g>"</string>
<string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> eftir"</string>
+ <string name="screen_zoom_summary_small" msgid="5867245310241621570">"Lítið"</string>
+ <string name="screen_zoom_summary_default" msgid="2247006805614056507">"Sjálfgefið"</string>
+ <string name="screen_zoom_summary_large" msgid="4835294730065424084">"Stórt"</string>
+ <string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"Stærra"</string>
+ <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Stærst"</string>
+ <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Sérsniðið (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-it/strings.xml b/packages/SettingsLib/res/values-it/strings.xml
index 40802bc..84ff78a 100644
--- a/packages/SettingsLib/res/values-it/strings.xml
+++ b/packages/SettingsLib/res/values-it/strings.xml
@@ -316,4 +316,10 @@
<string name="home" msgid="8263346537524314127">"Home page"</string>
<string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> fa"</string>
<string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> rimanenti"</string>
+ <string name="screen_zoom_summary_small" msgid="5867245310241621570">"Piccolo"</string>
+ <string name="screen_zoom_summary_default" msgid="2247006805614056507">"Predefinito"</string>
+ <string name="screen_zoom_summary_large" msgid="4835294730065424084">"Grande"</string>
+ <string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"Più grande"</string>
+ <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Massimo"</string>
+ <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Personalizzato (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-iw/strings.xml b/packages/SettingsLib/res/values-iw/strings.xml
index a651a3a..74ea372 100644
--- a/packages/SettingsLib/res/values-iw/strings.xml
+++ b/packages/SettingsLib/res/values-iw/strings.xml
@@ -278,8 +278,7 @@
<string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"הרץ מעבדי תצוגת אתר בהליך מבודד"</string>
<string name="select_webview_provider_title" msgid="4628592979751918907">"יישום WebView"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"הגדרת יישום WebView"</string>
- <!-- no translation found for select_webview_provider_toast_text (5466970498308266359) -->
- <skip />
+ <string name="select_webview_provider_toast_text" msgid="5466970498308266359">"אפשרות זו כבר אינה תקפה. נסה שוב."</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"המר להצפנת קבצים"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"המר..."</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"הצפנת קבצים כבר מוגדרת"</string>
@@ -317,4 +316,10 @@
<string name="home" msgid="8263346537524314127">"דף הבית"</string>
<string name="charge_length_format" msgid="8978516217024434156">"לפני <xliff:g id="ID_1">%1$s</xliff:g>"</string>
<string name="remaining_length_format" msgid="7886337596669190587">"נשארו <xliff:g id="ID_1">%1$s</xliff:g>"</string>
+ <string name="screen_zoom_summary_small" msgid="5867245310241621570">"קטן"</string>
+ <string name="screen_zoom_summary_default" msgid="2247006805614056507">"ברירת מחדל"</string>
+ <string name="screen_zoom_summary_large" msgid="4835294730065424084">"גדול"</string>
+ <string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"יותר גדול"</string>
+ <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"הכי גדול"</string>
+ <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"מותאם אישית (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-ja/strings.xml b/packages/SettingsLib/res/values-ja/strings.xml
index e17db51..2556d99 100644
--- a/packages/SettingsLib/res/values-ja/strings.xml
+++ b/packages/SettingsLib/res/values-ja/strings.xml
@@ -318,4 +318,10 @@
<string name="home" msgid="8263346537524314127">"ホーム"</string>
<string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g>前"</string>
<string name="remaining_length_format" msgid="7886337596669190587">"あと <xliff:g id="ID_1">%1$s</xliff:g>"</string>
+ <string name="screen_zoom_summary_small" msgid="5867245310241621570">"小"</string>
+ <string name="screen_zoom_summary_default" msgid="2247006805614056507">"デフォルト"</string>
+ <string name="screen_zoom_summary_large" msgid="4835294730065424084">"大"</string>
+ <string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"特大"</string>
+ <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"最大"</string>
+ <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"カスタム(<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-ka-rGE/strings.xml b/packages/SettingsLib/res/values-ka-rGE/strings.xml
index 11fa8a6..29e9459 100644
--- a/packages/SettingsLib/res/values-ka-rGE/strings.xml
+++ b/packages/SettingsLib/res/values-ka-rGE/strings.xml
@@ -278,8 +278,7 @@
<string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"WebView ვიზუალიზატორების იზოლირებულ პროცესში გაშვება."</string>
<string name="select_webview_provider_title" msgid="4628592979751918907">"WebView რეალიზაცია"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"WebView რეალიზაციის დაყენება"</string>
- <!-- no translation found for select_webview_provider_toast_text (5466970498308266359) -->
- <skip />
+ <string name="select_webview_provider_toast_text" msgid="5466970498308266359">"თქვენი არჩევანი აღარ მოქმედებს. ცადეთ ხელახლა."</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"ფაილების დაშიფვრაზე გარდაქმნა"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"გარდაქმნა…"</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"უკვე დაშიფრულია ფაილების დონეზე"</string>
@@ -317,4 +316,10 @@
<string name="home" msgid="8263346537524314127">"მთავარი"</string>
<string name="charge_length_format" msgid="8978516217024434156">"გავიდა <xliff:g id="ID_1">%1$s</xliff:g>"</string>
<string name="remaining_length_format" msgid="7886337596669190587">"დარჩენილია <xliff:g id="ID_1">%1$s</xliff:g>"</string>
+ <string name="screen_zoom_summary_small" msgid="5867245310241621570">"პატარა"</string>
+ <string name="screen_zoom_summary_default" msgid="2247006805614056507">"ნაგულისხმევი"</string>
+ <string name="screen_zoom_summary_large" msgid="4835294730065424084">"დიდი"</string>
+ <string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"უფრო დიდი"</string>
+ <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"უდიდესი"</string>
+ <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"მორგებული (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-kk-rKZ/strings.xml b/packages/SettingsLib/res/values-kk-rKZ/strings.xml
index aae7449..fdd3f95 100644
--- a/packages/SettingsLib/res/values-kk-rKZ/strings.xml
+++ b/packages/SettingsLib/res/values-kk-rKZ/strings.xml
@@ -316,4 +316,10 @@
<string name="home" msgid="8263346537524314127">"Негізгі бет"</string>
<string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> бұрын"</string>
<string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> қалды"</string>
+ <string name="screen_zoom_summary_small" msgid="5867245310241621570">"Кішкентай"</string>
+ <string name="screen_zoom_summary_default" msgid="2247006805614056507">"Әдепкі"</string>
+ <string name="screen_zoom_summary_large" msgid="4835294730065424084">"Үлкен"</string>
+ <string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"Үлкенірек"</string>
+ <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Ең үлкен"</string>
+ <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Арнаулы (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-km-rKH/strings.xml b/packages/SettingsLib/res/values-km-rKH/strings.xml
index 4373c43..2cafa29 100644
--- a/packages/SettingsLib/res/values-km-rKH/strings.xml
+++ b/packages/SettingsLib/res/values-km-rKH/strings.xml
@@ -316,4 +316,10 @@
<string name="home" msgid="8263346537524314127">"ដើម"</string>
<string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> មុន"</string>
<string name="remaining_length_format" msgid="7886337596669190587">"នៅសល់ <xliff:g id="ID_1">%1$s</xliff:g>"</string>
+ <string name="screen_zoom_summary_small" msgid="5867245310241621570">"តូច"</string>
+ <string name="screen_zoom_summary_default" msgid="2247006805614056507">"លំនាំដើម"</string>
+ <string name="screen_zoom_summary_large" msgid="4835294730065424084">"ធំ"</string>
+ <string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"ធំជាង"</string>
+ <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"ធំបំផុត"</string>
+ <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"ផ្ទាល់ខ្លួន (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-kn-rIN/strings.xml b/packages/SettingsLib/res/values-kn-rIN/strings.xml
index f0d63fb..6d13b35 100644
--- a/packages/SettingsLib/res/values-kn-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-kn-rIN/strings.xml
@@ -278,8 +278,7 @@
<string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"ಪ್ರತ್ಯೇಕಗೊಳಿಸಿದ ಪ್ರಕ್ರಿಯೆಯಲ್ಲಿ WebView ರೆಂಡರರ್ ರನ್ ಮಾಡಿ."</string>
<string name="select_webview_provider_title" msgid="4628592979751918907">"WebView ಅನುಷ್ಠಾನಗೊಳಿಸುವಿಕೆ"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"WebView ಅನುಷ್ಠಾನಗೊಳಿಸುವಿಕೆಯನ್ನು ಹೊಂದಿಸಿ"</string>
- <!-- no translation found for select_webview_provider_toast_text (5466970498308266359) -->
- <skip />
+ <string name="select_webview_provider_toast_text" msgid="5466970498308266359">"ಈ ಆಯ್ಕೆಯು ಇನ್ನು ಮುಂದೆ ಮಾನ್ಯವಾಗಿರುವುದಿಲ್ಲ. ಮತ್ತೊಮ್ಮೆ ಪ್ರಯತ್ನಿಸಿ."</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"ಫೈಲ್ ಎನ್ಕ್ರಿಪ್ಶನ್ಗೆ ಪರಿವರ್ತಿಸು"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"ಪರಿವರ್ತಿಸು…"</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"ಫೈಲ್ ಈಗಾಗಲೇ ಎನ್ಕ್ರಿಪ್ಟ್ ಮಾಡಲಾಗಿದೆ"</string>
@@ -317,4 +316,10 @@
<string name="home" msgid="8263346537524314127">"ಮುಖಪುಟ"</string>
<string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> ಹಿಂದೆ"</string>
<string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> ಉಳಿದಿದೆ"</string>
+ <string name="screen_zoom_summary_small" msgid="5867245310241621570">"ಸಣ್ಣದು"</string>
+ <string name="screen_zoom_summary_default" msgid="2247006805614056507">"ಡಿಫಾಲ್ಟ್"</string>
+ <string name="screen_zoom_summary_large" msgid="4835294730065424084">"ದೊಡ್ಡದು"</string>
+ <string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"ಸ್ವಲ್ಪ ದೊಡ್ಡ"</string>
+ <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"ದೊಡ್ಡ"</string>
+ <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"ಕಸ್ಟಮ್ (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-ko/strings.xml b/packages/SettingsLib/res/values-ko/strings.xml
index a8b6c36..035793e 100644
--- a/packages/SettingsLib/res/values-ko/strings.xml
+++ b/packages/SettingsLib/res/values-ko/strings.xml
@@ -316,4 +316,10 @@
<string name="home" msgid="8263346537524314127">"홈"</string>
<string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> 전"</string>
<string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> 남음"</string>
+ <string name="screen_zoom_summary_small" msgid="5867245310241621570">"작게"</string>
+ <string name="screen_zoom_summary_default" msgid="2247006805614056507">"기본"</string>
+ <string name="screen_zoom_summary_large" msgid="4835294730065424084">"크게"</string>
+ <string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"더 크게"</string>
+ <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"가장 크게"</string>
+ <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"맞춤(<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-ky-rKG/strings.xml b/packages/SettingsLib/res/values-ky-rKG/strings.xml
index 6491d3c..8c43312 100644
--- a/packages/SettingsLib/res/values-ky-rKG/strings.xml
+++ b/packages/SettingsLib/res/values-ky-rKG/strings.xml
@@ -278,8 +278,7 @@
<string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"WebView рендерерлерин корголгон процессте иштетүү."</string>
<string name="select_webview_provider_title" msgid="4628592979751918907">"WebView аткарылышы"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"WebView аткарылышын коюу"</string>
- <!-- no translation found for select_webview_provider_toast_text (5466970498308266359) -->
- <skip />
+ <string name="select_webview_provider_toast_text" msgid="5466970498308266359">"Тандалган нерсе жараксыз болуп калган. Кайра аракет кылыңыз."</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"Файл шифрлөөсүнө айландыруу"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Айландыруу…"</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Файл мурунтан эле шифрленген"</string>
@@ -317,4 +316,10 @@
<string name="home" msgid="8263346537524314127">"Башкы бет"</string>
<string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> мурун"</string>
<string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> калды"</string>
+ <string name="screen_zoom_summary_small" msgid="5867245310241621570">"Кичине"</string>
+ <string name="screen_zoom_summary_default" msgid="2247006805614056507">"Демейки"</string>
+ <string name="screen_zoom_summary_large" msgid="4835294730065424084">"Чоң"</string>
+ <string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"Чоңураак"</string>
+ <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Эң чоң"</string>
+ <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Ыңгайлаштырылган (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-lo-rLA/strings.xml b/packages/SettingsLib/res/values-lo-rLA/strings.xml
index cf90c4b..f158d44 100644
--- a/packages/SettingsLib/res/values-lo-rLA/strings.xml
+++ b/packages/SettingsLib/res/values-lo-rLA/strings.xml
@@ -316,4 +316,10 @@
<string name="home" msgid="8263346537524314127">"ໜ້າຫຼັກ"</string>
<string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> ກ່ອນນີ້"</string>
<string name="remaining_length_format" msgid="7886337596669190587">"ຍັງເຫຼືອ <xliff:g id="ID_1">%1$s</xliff:g>"</string>
+ <string name="screen_zoom_summary_small" msgid="5867245310241621570">"ນ້ອຍ"</string>
+ <string name="screen_zoom_summary_default" msgid="2247006805614056507">"ຄ່າເລີ່ມຕົ້ນ"</string>
+ <string name="screen_zoom_summary_large" msgid="4835294730065424084">"ໃຫຍ່"</string>
+ <string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"ໃຫຍ່ກວ່າ"</string>
+ <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"ໃຫຍ່ທີ່ສຸດ"</string>
+ <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"ປັບແຕ່ງເອງ (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-lt/strings.xml b/packages/SettingsLib/res/values-lt/strings.xml
index fd245f3..d5cea8e 100644
--- a/packages/SettingsLib/res/values-lt/strings.xml
+++ b/packages/SettingsLib/res/values-lt/strings.xml
@@ -316,4 +316,10 @@
<string name="home" msgid="8263346537524314127">"Pagrindinis ekranas"</string>
<string name="charge_length_format" msgid="8978516217024434156">"Prieš <xliff:g id="ID_1">%1$s</xliff:g>"</string>
<string name="remaining_length_format" msgid="7886337596669190587">"Liko <xliff:g id="ID_1">%1$s</xliff:g>"</string>
+ <string name="screen_zoom_summary_small" msgid="5867245310241621570">"Mažas"</string>
+ <string name="screen_zoom_summary_default" msgid="2247006805614056507">"Numatytasis"</string>
+ <string name="screen_zoom_summary_large" msgid="4835294730065424084">"Didelis"</string>
+ <string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"Didesnis"</string>
+ <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Didžiausias"</string>
+ <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Tinkintas (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-lv/strings.xml b/packages/SettingsLib/res/values-lv/strings.xml
index b470fb54..ea6f4f9 100644
--- a/packages/SettingsLib/res/values-lv/strings.xml
+++ b/packages/SettingsLib/res/values-lv/strings.xml
@@ -316,4 +316,10 @@
<string name="home" msgid="8263346537524314127">"Sākums"</string>
<string name="charge_length_format" msgid="8978516217024434156">"Pirms šāda laika: <xliff:g id="ID_1">%1$s</xliff:g>"</string>
<string name="remaining_length_format" msgid="7886337596669190587">"Atlikušais laiks: <xliff:g id="ID_1">%1$s</xliff:g>"</string>
+ <string name="screen_zoom_summary_small" msgid="5867245310241621570">"Mazs"</string>
+ <string name="screen_zoom_summary_default" msgid="2247006805614056507">"Noklusējuma"</string>
+ <string name="screen_zoom_summary_large" msgid="4835294730065424084">"Liels"</string>
+ <string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"Lielāks"</string>
+ <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Vislielākais"</string>
+ <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Pielāgots (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-mk-rMK/strings.xml b/packages/SettingsLib/res/values-mk-rMK/strings.xml
index 7592cd3..e954cdf 100644
--- a/packages/SettingsLib/res/values-mk-rMK/strings.xml
+++ b/packages/SettingsLib/res/values-mk-rMK/strings.xml
@@ -316,4 +316,10 @@
<string name="home" msgid="8263346537524314127">"Почетна страница"</string>
<string name="charge_length_format" msgid="8978516217024434156">"Пред <xliff:g id="ID_1">%1$s</xliff:g>"</string>
<string name="remaining_length_format" msgid="7886337596669190587">"Преостанаа <xliff:g id="ID_1">%1$s</xliff:g>"</string>
+ <string name="screen_zoom_summary_small" msgid="5867245310241621570">"Мал"</string>
+ <string name="screen_zoom_summary_default" msgid="2247006805614056507">"Стандардно"</string>
+ <string name="screen_zoom_summary_large" msgid="4835294730065424084">"Голем"</string>
+ <string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"Поголем"</string>
+ <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Најголем"</string>
+ <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Приспособен (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-ml-rIN/strings.xml b/packages/SettingsLib/res/values-ml-rIN/strings.xml
index 13a7013..a4b3877 100644
--- a/packages/SettingsLib/res/values-ml-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-ml-rIN/strings.xml
@@ -278,8 +278,7 @@
<string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"ഒറ്റപ്പെട്ടൊരു പ്രോസസ്സിൽ WebView റെൻഡററുകൾ റൺ ചെയ്യുക."</string>
<string name="select_webview_provider_title" msgid="4628592979751918907">"WebView നടപ്പാക്കൽ"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"WebView നടപ്പാക്കൽ സജ്ജമാക്കുക"</string>
- <!-- no translation found for select_webview_provider_toast_text (5466970498308266359) -->
- <skip />
+ <string name="select_webview_provider_toast_text" msgid="5466970498308266359">"ഈ തിരഞ്ഞെടുപ്പിന് തുടർന്നങ്ങോട്ട് സാധുതയില്ല. വീണ്ടും ശ്രമിക്കുക."</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"ഫയൽ എൻക്രിപ്ഷനിലേക്ക് പരിവർത്തിപ്പിക്കുക"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"പരിവർത്തിപ്പിക്കുക…"</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"ഇതിനകം തന്നെ ഫയൽ എൻക്രിപ്റ്റ് ചെയ്തു"</string>
@@ -317,4 +316,10 @@
<string name="home" msgid="8263346537524314127">"ഹോം"</string>
<string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> മുമ്പ്"</string>
<string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> ശേഷിക്കുന്നു"</string>
+ <string name="screen_zoom_summary_small" msgid="5867245310241621570">"ചെറുത്"</string>
+ <string name="screen_zoom_summary_default" msgid="2247006805614056507">"ഡിഫോൾട്ട്"</string>
+ <string name="screen_zoom_summary_large" msgid="4835294730065424084">"വലുത്"</string>
+ <string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"കൂടുതൽ വലുത്"</string>
+ <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"ഏറ്റവും വലുത്"</string>
+ <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"ഇഷ്ടാനുസൃതം ( <xliff:g id="DENSITYDPI">%d</xliff:g> )"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-mn-rMN/strings.xml b/packages/SettingsLib/res/values-mn-rMN/strings.xml
index a77e32e..d989ef8 100644
--- a/packages/SettingsLib/res/values-mn-rMN/strings.xml
+++ b/packages/SettingsLib/res/values-mn-rMN/strings.xml
@@ -316,4 +316,10 @@
<string name="home" msgid="8263346537524314127">"Нүүр"</string>
<string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> өмнө"</string>
<string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> үлдсэн"</string>
+ <string name="screen_zoom_summary_small" msgid="5867245310241621570">"Жижиг"</string>
+ <string name="screen_zoom_summary_default" msgid="2247006805614056507">"Өгөгдмөл"</string>
+ <string name="screen_zoom_summary_large" msgid="4835294730065424084">"Том"</string>
+ <string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"Илүү том"</string>
+ <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Хамгийн том"</string>
+ <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Тогтмол утга (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-mr-rIN/strings.xml b/packages/SettingsLib/res/values-mr-rIN/strings.xml
index 4f12e46..d363874 100644
--- a/packages/SettingsLib/res/values-mr-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-mr-rIN/strings.xml
@@ -278,8 +278,7 @@
<string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"एक वेगळ्या प्रक्रियेत WebView प्रस्तुतकर्ते चालवा."</string>
<string name="select_webview_provider_title" msgid="4628592979751918907">"वेबदृश्य अंमलबजावणी"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"वेबदृश्य अंमलबजावणी सेट करा"</string>
- <!-- no translation found for select_webview_provider_toast_text (5466970498308266359) -->
- <skip />
+ <string name="select_webview_provider_toast_text" msgid="5466970498308266359">"ही निवड यापुढे वैध असणार नाही. पुन्हा प्रयत्न करा."</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"फाईल कूटबद्धीकरणावर रूपांतरित करा"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"रूपांतरित करा..."</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"फाईल आधीपासून कूटबद्ध केली"</string>
@@ -317,4 +316,10 @@
<string name="home" msgid="8263346537524314127">"मुख्यपृष्ठ"</string>
<string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> पूर्वी"</string>
<string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> शिल्लक"</string>
+ <string name="screen_zoom_summary_small" msgid="5867245310241621570">"लहान"</string>
+ <string name="screen_zoom_summary_default" msgid="2247006805614056507">"डीफॉल्ट"</string>
+ <string name="screen_zoom_summary_large" msgid="4835294730065424084">"मोठा"</string>
+ <string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"आणखी मोठा"</string>
+ <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"सर्वात मोठा"</string>
+ <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"सानुकूल करा (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-ms-rMY/strings.xml b/packages/SettingsLib/res/values-ms-rMY/strings.xml
index 6ba7d20..ea79a46 100644
--- a/packages/SettingsLib/res/values-ms-rMY/strings.xml
+++ b/packages/SettingsLib/res/values-ms-rMY/strings.xml
@@ -316,4 +316,10 @@
<string name="home" msgid="8263346537524314127">"Skrin Utama"</string>
<string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> yang lalu"</string>
<string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> lagi"</string>
+ <string name="screen_zoom_summary_small" msgid="5867245310241621570">"Kecil"</string>
+ <string name="screen_zoom_summary_default" msgid="2247006805614056507">"Lalai"</string>
+ <string name="screen_zoom_summary_large" msgid="4835294730065424084">"Besar"</string>
+ <string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"Lebih besar"</string>
+ <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Terbesar"</string>
+ <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Tersuai (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-my-rMM/strings.xml b/packages/SettingsLib/res/values-my-rMM/strings.xml
index 5c1a5ee..74e0f29 100644
--- a/packages/SettingsLib/res/values-my-rMM/strings.xml
+++ b/packages/SettingsLib/res/values-my-rMM/strings.xml
@@ -316,4 +316,10 @@
<string name="home" msgid="8263346537524314127">"ပင်မ"</string>
<string name="charge_length_format" msgid="8978516217024434156">"ပြီးခဲ့သည့် <xliff:g id="ID_1">%1$s</xliff:g> က"</string>
<string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> ကျန်ပါသည်"</string>
+ <string name="screen_zoom_summary_small" msgid="5867245310241621570">"သေး"</string>
+ <string name="screen_zoom_summary_default" msgid="2247006805614056507">"မူရင်း"</string>
+ <string name="screen_zoom_summary_large" msgid="4835294730065424084">"ကြီး"</string>
+ <string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"ပိုကြီး"</string>
+ <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"အကြီးဆုံး"</string>
+ <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"စိတ်ကြိုက် (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-nb/strings.xml b/packages/SettingsLib/res/values-nb/strings.xml
index de6faf4..1a0b468 100644
--- a/packages/SettingsLib/res/values-nb/strings.xml
+++ b/packages/SettingsLib/res/values-nb/strings.xml
@@ -316,4 +316,10 @@
<string name="home" msgid="8263346537524314127">"Startside"</string>
<string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> siden"</string>
<string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> gjenstår"</string>
+ <string name="screen_zoom_summary_small" msgid="5867245310241621570">"Liten"</string>
+ <string name="screen_zoom_summary_default" msgid="2247006805614056507">"Standard"</string>
+ <string name="screen_zoom_summary_large" msgid="4835294730065424084">"Stor"</string>
+ <string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"Større"</string>
+ <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Størst"</string>
+ <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Egendefinert (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-ne-rNP/strings.xml b/packages/SettingsLib/res/values-ne-rNP/strings.xml
index 47ec137..a001cab 100644
--- a/packages/SettingsLib/res/values-ne-rNP/strings.xml
+++ b/packages/SettingsLib/res/values-ne-rNP/strings.xml
@@ -278,8 +278,7 @@
<string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"एउटा पृथक प्रक्रियामा वेबभ्यु रेन्डररहरू चलाउनुहोस्।"</string>
<string name="select_webview_provider_title" msgid="4628592979751918907">"WebView कार्यान्वयन"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"WebView कार्यान्वयन सेट गर्नुहोस्"</string>
- <!-- no translation found for select_webview_provider_toast_text (5466970498308266359) -->
- <skip />
+ <string name="select_webview_provider_toast_text" msgid="5466970498308266359">"यो छनोट अब मान्य छैन। फेरि प्रयास गर्नुहोस्।"</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"फाइल इन्क्रिप्सनमा रूपान्तरण गर्नुहोस्"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"रुपान्तरण गर्नुहोस्…"</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"पहिल्यै फाइल इन्क्रिप्ट गरिएको छ"</string>
@@ -317,4 +316,10 @@
<string name="home" msgid="8263346537524314127">"गृह"</string>
<string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> पहिले"</string>
<string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> बाँकी"</string>
+ <string name="screen_zoom_summary_small" msgid="5867245310241621570">"सानो"</string>
+ <string name="screen_zoom_summary_default" msgid="2247006805614056507">"पूर्वनिर्धारित"</string>
+ <string name="screen_zoom_summary_large" msgid="4835294730065424084">"ठूलो"</string>
+ <string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"अझ ठूलो"</string>
+ <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"सबैभन्दा ठूलो"</string>
+ <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"अनुकूलन (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-nl/strings.xml b/packages/SettingsLib/res/values-nl/strings.xml
index 9f72db5..301e327 100644
--- a/packages/SettingsLib/res/values-nl/strings.xml
+++ b/packages/SettingsLib/res/values-nl/strings.xml
@@ -316,4 +316,10 @@
<string name="home" msgid="8263346537524314127">"Startpagina"</string>
<string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> geleden"</string>
<string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> resterend"</string>
+ <string name="screen_zoom_summary_small" msgid="5867245310241621570">"Klein"</string>
+ <string name="screen_zoom_summary_default" msgid="2247006805614056507">"Standaard"</string>
+ <string name="screen_zoom_summary_large" msgid="4835294730065424084">"Groot"</string>
+ <string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"Groter"</string>
+ <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Grootst"</string>
+ <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Aangepast (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-pa-rIN/strings.xml b/packages/SettingsLib/res/values-pa-rIN/strings.xml
index 8625b90..c792ec9 100644
--- a/packages/SettingsLib/res/values-pa-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-pa-rIN/strings.xml
@@ -278,8 +278,7 @@
<string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"ਕਿਸੇ ਵੱਖ ਕੀਤੀ ਗਈ ਪ੍ਰਕਿਰਿਆ ਵਿੱਚ WebView ਰੈਂਡਰਰਾਂ ਨੂੰ ਚਲਾਓ।"</string>
<string name="select_webview_provider_title" msgid="4628592979751918907">"WebView ਅਮਲ"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"WebView ਅਮਲ ਸੈੱਟ ਕਰੋ"</string>
- <!-- no translation found for select_webview_provider_toast_text (5466970498308266359) -->
- <skip />
+ <string name="select_webview_provider_toast_text" msgid="5466970498308266359">"ਇਹ ਚੋਣ ਹੁਣ ਵੈਧ ਨਹੀਂ ਹੈ। ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ।"</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"ਫ਼ਾਈਲ ਇਨਕ੍ਰਿਪਸ਼ਨ ਵਿੱਚ ਤਬਦੀਲ ਕਰੋ"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"ਤਬਦੀਲ ਕਰੋ ..."</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"ਫ਼ਾਈਲ ਪਹਿਲਾਂ ਤੋਂ ਇਨਕ੍ਰਿਪਟਡ ਹੈ"</string>
@@ -317,4 +316,10 @@
<string name="home" msgid="8263346537524314127">"ਮੁੱਖ ਸਕ੍ਰੀਨ"</string>
<string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> ਪਹਿਲਾਂ"</string>
<string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> ਬਾਕੀ"</string>
+ <string name="screen_zoom_summary_small" msgid="5867245310241621570">"ਛੋਟਾ"</string>
+ <string name="screen_zoom_summary_default" msgid="2247006805614056507">"ਪੂਰਵ-ਨਿਰਧਾਰਤ"</string>
+ <string name="screen_zoom_summary_large" msgid="4835294730065424084">"ਵੱਡਾ"</string>
+ <string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"ਥੋੜ੍ਹਾ ਵੱਡਾ"</string>
+ <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"ਸਭ ਤੋਂ ਵੱਡਾ"</string>
+ <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"ਵਿਸ਼ੇਸ਼-ਵਿਉਂਤਬੱਧ (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-pl/strings.xml b/packages/SettingsLib/res/values-pl/strings.xml
index b4c030d..8aad98b1 100644
--- a/packages/SettingsLib/res/values-pl/strings.xml
+++ b/packages/SettingsLib/res/values-pl/strings.xml
@@ -316,4 +316,10 @@
<string name="home" msgid="8263346537524314127">"Ekran główny"</string>
<string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> temu"</string>
<string name="remaining_length_format" msgid="7886337596669190587">"Pozostało <xliff:g id="ID_1">%1$s</xliff:g>"</string>
+ <string name="screen_zoom_summary_small" msgid="5867245310241621570">"Małe"</string>
+ <string name="screen_zoom_summary_default" msgid="2247006805614056507">"Domyślne"</string>
+ <string name="screen_zoom_summary_large" msgid="4835294730065424084">"Duże"</string>
+ <string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"Większe"</string>
+ <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Największe"</string>
+ <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Niestandardowe (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-pt-rBR/strings.xml b/packages/SettingsLib/res/values-pt-rBR/strings.xml
index e76535a..c05458b 100644
--- a/packages/SettingsLib/res/values-pt-rBR/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rBR/strings.xml
@@ -316,4 +316,10 @@
<string name="home" msgid="8263346537524314127">"Início"</string>
<string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> atrás"</string>
<string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> restante(s)"</string>
+ <string name="screen_zoom_summary_small" msgid="5867245310241621570">"Pequena"</string>
+ <string name="screen_zoom_summary_default" msgid="2247006805614056507">"Padrão"</string>
+ <string name="screen_zoom_summary_large" msgid="4835294730065424084">"Grande"</string>
+ <string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"Muito grande"</string>
+ <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Maior"</string>
+ <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Personalizada (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-pt-rPT/strings.xml b/packages/SettingsLib/res/values-pt-rPT/strings.xml
index 7e4744c..402bc86 100644
--- a/packages/SettingsLib/res/values-pt-rPT/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rPT/strings.xml
@@ -316,4 +316,10 @@
<string name="home" msgid="8263346537524314127">"Página inicial"</string>
<string name="charge_length_format" msgid="8978516217024434156">"Há <xliff:g id="ID_1">%1$s</xliff:g>"</string>
<string name="remaining_length_format" msgid="7886337596669190587">"Resta(m) <xliff:g id="ID_1">%1$s</xliff:g>"</string>
+ <string name="screen_zoom_summary_small" msgid="5867245310241621570">"Pequeno"</string>
+ <string name="screen_zoom_summary_default" msgid="2247006805614056507">"Predefinição"</string>
+ <string name="screen_zoom_summary_large" msgid="4835294730065424084">"Grande"</string>
+ <string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"Maior"</string>
+ <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"O maior"</string>
+ <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Personalizado (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-pt/strings.xml b/packages/SettingsLib/res/values-pt/strings.xml
index e76535a..c05458b 100644
--- a/packages/SettingsLib/res/values-pt/strings.xml
+++ b/packages/SettingsLib/res/values-pt/strings.xml
@@ -316,4 +316,10 @@
<string name="home" msgid="8263346537524314127">"Início"</string>
<string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> atrás"</string>
<string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> restante(s)"</string>
+ <string name="screen_zoom_summary_small" msgid="5867245310241621570">"Pequena"</string>
+ <string name="screen_zoom_summary_default" msgid="2247006805614056507">"Padrão"</string>
+ <string name="screen_zoom_summary_large" msgid="4835294730065424084">"Grande"</string>
+ <string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"Muito grande"</string>
+ <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Maior"</string>
+ <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Personalizada (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-ro/strings.xml b/packages/SettingsLib/res/values-ro/strings.xml
index 5b712d0..d5e0769 100644
--- a/packages/SettingsLib/res/values-ro/strings.xml
+++ b/packages/SettingsLib/res/values-ro/strings.xml
@@ -316,4 +316,10 @@
<string name="home" msgid="8263346537524314127">"Ecranul principal"</string>
<string name="charge_length_format" msgid="8978516217024434156">"Acum <xliff:g id="ID_1">%1$s</xliff:g>"</string>
<string name="remaining_length_format" msgid="7886337596669190587">"Timp rămas: <xliff:g id="ID_1">%1$s</xliff:g>"</string>
+ <string name="screen_zoom_summary_small" msgid="5867245310241621570">"Mic"</string>
+ <string name="screen_zoom_summary_default" msgid="2247006805614056507">"Prestabilit"</string>
+ <string name="screen_zoom_summary_large" msgid="4835294730065424084">"Mare"</string>
+ <string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"Mai mare"</string>
+ <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Cel mai mare"</string>
+ <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Personalizat (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-ru/strings.xml b/packages/SettingsLib/res/values-ru/strings.xml
index b233c4c..7ad9f16 100644
--- a/packages/SettingsLib/res/values-ru/strings.xml
+++ b/packages/SettingsLib/res/values-ru/strings.xml
@@ -316,4 +316,10 @@
<string name="home" msgid="8263346537524314127">"Главная"</string>
<string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> назад"</string>
<string name="remaining_length_format" msgid="7886337596669190587">"Осталось <xliff:g id="ID_1">%1$s</xliff:g>"</string>
+ <string name="screen_zoom_summary_small" msgid="5867245310241621570">"Мелкий"</string>
+ <string name="screen_zoom_summary_default" msgid="2247006805614056507">"По умолчанию"</string>
+ <string name="screen_zoom_summary_large" msgid="4835294730065424084">"Крупный"</string>
+ <string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"Очень крупный"</string>
+ <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Максимальный"</string>
+ <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Другой (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-si-rLK/strings.xml b/packages/SettingsLib/res/values-si-rLK/strings.xml
index c8af144..4c73219 100644
--- a/packages/SettingsLib/res/values-si-rLK/strings.xml
+++ b/packages/SettingsLib/res/values-si-rLK/strings.xml
@@ -278,8 +278,7 @@
<string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"හුදකලා වූ ක්රියාවලියක WebView විදහා දැක්වීම් ධාවනය කරන්න."</string>
<string name="select_webview_provider_title" msgid="4628592979751918907">"WebView ක්රියාත්මක කිරීම"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"WebView ක්රියාත්මක කිරීම සකසන්න"</string>
- <!-- no translation found for select_webview_provider_toast_text (5466970498308266359) -->
- <skip />
+ <string name="select_webview_provider_toast_text" msgid="5466970498308266359">"මෙම තෝරා ගැනීම තව දුරටත් වලංගු නැත. නැවත උත්සාහ කරන්න."</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"ගොනු සංකේතනයට පරිවර්තනය කරන්න"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"පරිවර්තනය කරන්න..."</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"දැනටමත් ගොනුව සංකේතනය කර ඇත"</string>
@@ -317,4 +316,10 @@
<string name="home" msgid="8263346537524314127">"මුල් පිටුව"</string>
<string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g>කට පෙර"</string>
<string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g>ක් ඉතිරිය"</string>
+ <string name="screen_zoom_summary_small" msgid="5867245310241621570">"කුඩා"</string>
+ <string name="screen_zoom_summary_default" msgid="2247006805614056507">"පෙරනිමි"</string>
+ <string name="screen_zoom_summary_large" msgid="4835294730065424084">"විශාල"</string>
+ <string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"වඩා විශාල"</string>
+ <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"විශාලතම"</string>
+ <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"අභිරුචි (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-sk/strings.xml b/packages/SettingsLib/res/values-sk/strings.xml
index 2c7a3b7..e5c9805 100644
--- a/packages/SettingsLib/res/values-sk/strings.xml
+++ b/packages/SettingsLib/res/values-sk/strings.xml
@@ -316,4 +316,10 @@
<string name="home" msgid="8263346537524314127">"Domov"</string>
<string name="charge_length_format" msgid="8978516217024434156">"pred <xliff:g id="ID_1">%1$s</xliff:g>"</string>
<string name="remaining_length_format" msgid="7886337596669190587">"Zostáva <xliff:g id="ID_1">%1$s</xliff:g>"</string>
+ <string name="screen_zoom_summary_small" msgid="5867245310241621570">"Malé"</string>
+ <string name="screen_zoom_summary_default" msgid="2247006805614056507">"Predvolená"</string>
+ <string name="screen_zoom_summary_large" msgid="4835294730065424084">"Veľké"</string>
+ <string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"Väčšie"</string>
+ <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Najväčšie"</string>
+ <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Vlastné (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-sl/strings.xml b/packages/SettingsLib/res/values-sl/strings.xml
index 62797c3..8257e3c 100644
--- a/packages/SettingsLib/res/values-sl/strings.xml
+++ b/packages/SettingsLib/res/values-sl/strings.xml
@@ -316,4 +316,10 @@
<string name="home" msgid="8263346537524314127">"Začetni zaslon"</string>
<string name="charge_length_format" msgid="8978516217024434156">"Pred toliko časa: <xliff:g id="ID_1">%1$s</xliff:g>"</string>
<string name="remaining_length_format" msgid="7886337596669190587">"Še <xliff:g id="ID_1">%1$s</xliff:g>"</string>
+ <string name="screen_zoom_summary_small" msgid="5867245310241621570">"Majhno"</string>
+ <string name="screen_zoom_summary_default" msgid="2247006805614056507">"Privzeto"</string>
+ <string name="screen_zoom_summary_large" msgid="4835294730065424084">"Veliko"</string>
+ <string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"Večje"</string>
+ <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Največje"</string>
+ <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Po meri (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-sq-rAL/strings.xml b/packages/SettingsLib/res/values-sq-rAL/strings.xml
index 0a069de..4a67348 100644
--- a/packages/SettingsLib/res/values-sq-rAL/strings.xml
+++ b/packages/SettingsLib/res/values-sq-rAL/strings.xml
@@ -316,4 +316,10 @@
<string name="home" msgid="8263346537524314127">"Kreu"</string>
<string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> më parë"</string>
<string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> të mbetura"</string>
+ <string name="screen_zoom_summary_small" msgid="5867245310241621570">"I vogël"</string>
+ <string name="screen_zoom_summary_default" msgid="2247006805614056507">"I parazgjedhur"</string>
+ <string name="screen_zoom_summary_large" msgid="4835294730065424084">"I madh"</string>
+ <string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"Më i madh"</string>
+ <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Më i madhi"</string>
+ <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"I personalizuar (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-sr/strings.xml b/packages/SettingsLib/res/values-sr/strings.xml
index 61a87b5..eaf7ac5 100644
--- a/packages/SettingsLib/res/values-sr/strings.xml
+++ b/packages/SettingsLib/res/values-sr/strings.xml
@@ -316,4 +316,10 @@
<string name="home" msgid="8263346537524314127">"Почетни"</string>
<string name="charge_length_format" msgid="8978516217024434156">"Пре <xliff:g id="ID_1">%1$s</xliff:g>"</string>
<string name="remaining_length_format" msgid="7886337596669190587">"Још <xliff:g id="ID_1">%1$s</xliff:g>"</string>
+ <string name="screen_zoom_summary_small" msgid="5867245310241621570">"Мали"</string>
+ <string name="screen_zoom_summary_default" msgid="2247006805614056507">"Подразумевано"</string>
+ <string name="screen_zoom_summary_large" msgid="4835294730065424084">"Велики"</string>
+ <string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"Већи"</string>
+ <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Највећи"</string>
+ <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Прилагођени (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-sv/strings.xml b/packages/SettingsLib/res/values-sv/strings.xml
index 1de7317..b019672 100644
--- a/packages/SettingsLib/res/values-sv/strings.xml
+++ b/packages/SettingsLib/res/values-sv/strings.xml
@@ -316,4 +316,10 @@
<string name="home" msgid="8263346537524314127">"Startsida"</string>
<string name="charge_length_format" msgid="8978516217024434156">"för <xliff:g id="ID_1">%1$s</xliff:g> sedan"</string>
<string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> kvar"</string>
+ <string name="screen_zoom_summary_small" msgid="5867245310241621570">"Små"</string>
+ <string name="screen_zoom_summary_default" msgid="2247006805614056507">"Standardinställning"</string>
+ <string name="screen_zoom_summary_large" msgid="4835294730065424084">"Stora"</string>
+ <string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"Större"</string>
+ <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Störst"</string>
+ <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Anpassad (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-sw/strings.xml b/packages/SettingsLib/res/values-sw/strings.xml
index c02c256..3daa90f 100644
--- a/packages/SettingsLib/res/values-sw/strings.xml
+++ b/packages/SettingsLib/res/values-sw/strings.xml
@@ -316,4 +316,10 @@
<string name="home" msgid="8263346537524314127">"Mwanzo"</string>
<string name="charge_length_format" msgid="8978516217024434156">"Zimepita <xliff:g id="ID_1">%1$s</xliff:g>"</string>
<string name="remaining_length_format" msgid="7886337596669190587">"Zimesalia <xliff:g id="ID_1">%1$s</xliff:g>"</string>
+ <string name="screen_zoom_summary_small" msgid="5867245310241621570">"Ndogo"</string>
+ <string name="screen_zoom_summary_default" msgid="2247006805614056507">"Chaguo-msingi"</string>
+ <string name="screen_zoom_summary_large" msgid="4835294730065424084">"Kubwa"</string>
+ <string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"Kubwa kiasi"</string>
+ <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Kubwa zaidi"</string>
+ <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Kiwango maalum (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-ta-rIN/strings.xml b/packages/SettingsLib/res/values-ta-rIN/strings.xml
index d28fe75..574d105 100644
--- a/packages/SettingsLib/res/values-ta-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-ta-rIN/strings.xml
@@ -316,4 +316,10 @@
<string name="home" msgid="8263346537524314127">"முகப்பு"</string>
<string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> முன்"</string>
<string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> உள்ளது"</string>
+ <string name="screen_zoom_summary_small" msgid="5867245310241621570">"சிறியது"</string>
+ <string name="screen_zoom_summary_default" msgid="2247006805614056507">"இயல்பு"</string>
+ <string name="screen_zoom_summary_large" msgid="4835294730065424084">"பெரியது"</string>
+ <string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"கொஞ்சம் பெரியது"</string>
+ <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"மிகப் பெரியது"</string>
+ <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"தனிப்பயன் (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-te-rIN/strings.xml b/packages/SettingsLib/res/values-te-rIN/strings.xml
index 9b6694c..2389112 100644
--- a/packages/SettingsLib/res/values-te-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-te-rIN/strings.xml
@@ -316,4 +316,10 @@
<string name="home" msgid="8263346537524314127">"హోమ్"</string>
<string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> క్రితం"</string>
<string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> మిగిలి ఉంది"</string>
+ <string name="screen_zoom_summary_small" msgid="5867245310241621570">"చిన్నగా"</string>
+ <string name="screen_zoom_summary_default" msgid="2247006805614056507">"డిఫాల్ట్"</string>
+ <string name="screen_zoom_summary_large" msgid="4835294730065424084">"పెద్దగా"</string>
+ <string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"చాలా పెద్దగా"</string>
+ <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"అతి పెద్దగా"</string>
+ <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"అనుకూలం (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-th/strings.xml b/packages/SettingsLib/res/values-th/strings.xml
index 5880b98..0f6f78c 100644
--- a/packages/SettingsLib/res/values-th/strings.xml
+++ b/packages/SettingsLib/res/values-th/strings.xml
@@ -278,8 +278,7 @@
<string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"เรียกใช้โหมดแสดงภาพ WebView ในการดำเนินการที่แยกออกมา"</string>
<string name="select_webview_provider_title" msgid="4628592979751918907">"การใช้งาน WebView"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"ตั้งค่าการใช้งาน WebView"</string>
- <!-- no translation found for select_webview_provider_toast_text (5466970498308266359) -->
- <skip />
+ <string name="select_webview_provider_toast_text" msgid="5466970498308266359">"ตัวเลือกนี้ใช้ไม่ได้อีกต่อไป โปรดลองอีกครั้ง"</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"แปลงเป็นการเข้ารหัสไฟล์"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"แปลง…"</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"เข้ารหัสไฟล์แล้ว"</string>
@@ -317,4 +316,10 @@
<string name="home" msgid="8263346537524314127">"หน้าแรก"</string>
<string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g>ที่ผ่านมา"</string>
<string name="remaining_length_format" msgid="7886337596669190587">"เหลือ <xliff:g id="ID_1">%1$s</xliff:g>"</string>
+ <string name="screen_zoom_summary_small" msgid="5867245310241621570">"เล็ก"</string>
+ <string name="screen_zoom_summary_default" msgid="2247006805614056507">"ค่าเริ่มต้น"</string>
+ <string name="screen_zoom_summary_large" msgid="4835294730065424084">"ใหญ่"</string>
+ <string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"ใหญ่ขึ้น"</string>
+ <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"ใหญ่ที่สุด"</string>
+ <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"กำหนดเอง (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-tl/strings.xml b/packages/SettingsLib/res/values-tl/strings.xml
index 3764d22..ef3dde7 100644
--- a/packages/SettingsLib/res/values-tl/strings.xml
+++ b/packages/SettingsLib/res/values-tl/strings.xml
@@ -316,4 +316,10 @@
<string name="home" msgid="8263346537524314127">"Home"</string>
<string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> na ang nakalipas"</string>
<string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> na lang"</string>
+ <string name="screen_zoom_summary_small" msgid="5867245310241621570">"Maliit"</string>
+ <string name="screen_zoom_summary_default" msgid="2247006805614056507">"Default"</string>
+ <string name="screen_zoom_summary_large" msgid="4835294730065424084">"Malaki"</string>
+ <string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"Mas malaki"</string>
+ <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Pinakamalaki"</string>
+ <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Custom (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-tr/strings.xml b/packages/SettingsLib/res/values-tr/strings.xml
index 0a2c654..4b7490d 100644
--- a/packages/SettingsLib/res/values-tr/strings.xml
+++ b/packages/SettingsLib/res/values-tr/strings.xml
@@ -316,4 +316,10 @@
<string name="home" msgid="8263346537524314127">"Ana Ekran"</string>
<string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> önce"</string>
<string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> kaldı"</string>
+ <string name="screen_zoom_summary_small" msgid="5867245310241621570">"Küçük"</string>
+ <string name="screen_zoom_summary_default" msgid="2247006805614056507">"Varsayılan"</string>
+ <string name="screen_zoom_summary_large" msgid="4835294730065424084">"Büyük"</string>
+ <string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"Daha büyük"</string>
+ <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"En büyük"</string>
+ <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Özel (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-uk/strings.xml b/packages/SettingsLib/res/values-uk/strings.xml
index 5b88647..5e044c3 100644
--- a/packages/SettingsLib/res/values-uk/strings.xml
+++ b/packages/SettingsLib/res/values-uk/strings.xml
@@ -316,4 +316,10 @@
<string name="home" msgid="8263346537524314127">"Головний екран"</string>
<string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> тому"</string>
<string name="remaining_length_format" msgid="7886337596669190587">"Залишилося <xliff:g id="ID_1">%1$s</xliff:g>"</string>
+ <string name="screen_zoom_summary_small" msgid="5867245310241621570">"Малі елементи"</string>
+ <string name="screen_zoom_summary_default" msgid="2247006805614056507">"За умовчанням"</string>
+ <string name="screen_zoom_summary_large" msgid="4835294730065424084">"Великі елементи"</string>
+ <string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"Більші елементи"</string>
+ <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Найбільші елементи"</string>
+ <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Спеціальний масштаб (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-ur-rPK/strings.xml b/packages/SettingsLib/res/values-ur-rPK/strings.xml
index e066736..6d3c6c4 100644
--- a/packages/SettingsLib/res/values-ur-rPK/strings.xml
+++ b/packages/SettingsLib/res/values-ur-rPK/strings.xml
@@ -316,4 +316,10 @@
<string name="home" msgid="8263346537524314127">"ہوم"</string>
<string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> قبل"</string>
<string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> باقی ہیں"</string>
+ <string name="screen_zoom_summary_small" msgid="5867245310241621570">"چھوٹا"</string>
+ <string name="screen_zoom_summary_default" msgid="2247006805614056507">"ڈیفالٹ"</string>
+ <string name="screen_zoom_summary_large" msgid="4835294730065424084">"بڑا"</string>
+ <string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"قدرے بڑا"</string>
+ <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"سب سے بڑا"</string>
+ <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"حسب ضرورت (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-uz-rUZ/strings.xml b/packages/SettingsLib/res/values-uz-rUZ/strings.xml
index 23e8b0f..ec04120 100644
--- a/packages/SettingsLib/res/values-uz-rUZ/strings.xml
+++ b/packages/SettingsLib/res/values-uz-rUZ/strings.xml
@@ -278,8 +278,7 @@
<string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"WebView renderlovchilarini alohida jarayonda ishga tushirish."</string>
<string name="select_webview_provider_title" msgid="4628592979751918907">"WebView ta’minotchisi"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"WebView ta’minotchisini sozlash"</string>
- <!-- no translation found for select_webview_provider_toast_text (5466970498308266359) -->
- <skip />
+ <string name="select_webview_provider_toast_text" msgid="5466970498308266359">"Bu variant endi yaroqsiz. Qaytadan urining."</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"Faylli shifrga o‘girish"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"O‘girish…"</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Fayl allaqachon shifrlangan"</string>
@@ -317,4 +316,10 @@
<string name="home" msgid="8263346537524314127">"Bosh ekran"</string>
<string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> oldin"</string>
<string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> qoldi"</string>
+ <string name="screen_zoom_summary_small" msgid="5867245310241621570">"Kichkina"</string>
+ <string name="screen_zoom_summary_default" msgid="2247006805614056507">"Birlamchi"</string>
+ <string name="screen_zoom_summary_large" msgid="4835294730065424084">"Katta"</string>
+ <string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"Kattaroq"</string>
+ <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Eng katta"</string>
+ <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Moslashtirilgan (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-vi/strings.xml b/packages/SettingsLib/res/values-vi/strings.xml
index 27dd482..dd1d482 100644
--- a/packages/SettingsLib/res/values-vi/strings.xml
+++ b/packages/SettingsLib/res/values-vi/strings.xml
@@ -316,4 +316,10 @@
<string name="home" msgid="8263346537524314127">"Màn hình chính"</string>
<string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> trước"</string>
<string name="remaining_length_format" msgid="7886337596669190587">"Còn <xliff:g id="ID_1">%1$s</xliff:g>"</string>
+ <string name="screen_zoom_summary_small" msgid="5867245310241621570">"Nhỏ"</string>
+ <string name="screen_zoom_summary_default" msgid="2247006805614056507">"Mặc định"</string>
+ <string name="screen_zoom_summary_large" msgid="4835294730065424084">"Lớn"</string>
+ <string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"Lớn hơn"</string>
+ <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Lớn nhất"</string>
+ <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Tùy chỉnh (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-zh-rCN/strings.xml b/packages/SettingsLib/res/values-zh-rCN/strings.xml
index 73cd252..4117ae1 100644
--- a/packages/SettingsLib/res/values-zh-rCN/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rCN/strings.xml
@@ -316,4 +316,10 @@
<string name="home" msgid="8263346537524314127">"主屏幕"</string>
<string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g>前"</string>
<string name="remaining_length_format" msgid="7886337596669190587">"还剩 <xliff:g id="ID_1">%1$s</xliff:g>"</string>
+ <string name="screen_zoom_summary_small" msgid="5867245310241621570">"小"</string>
+ <string name="screen_zoom_summary_default" msgid="2247006805614056507">"默认"</string>
+ <string name="screen_zoom_summary_large" msgid="4835294730065424084">"大"</string>
+ <string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"较大"</string>
+ <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"最大"</string>
+ <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"自定义 (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-zh-rHK/strings.xml b/packages/SettingsLib/res/values-zh-rHK/strings.xml
index 944082f..1fb4c5e 100644
--- a/packages/SettingsLib/res/values-zh-rHK/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rHK/strings.xml
@@ -316,4 +316,10 @@
<string name="home" msgid="8263346537524314127">"主畫面"</string>
<string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g>前"</string>
<string name="remaining_length_format" msgid="7886337596669190587">"尚餘 <xliff:g id="ID_1">%1$s</xliff:g>"</string>
+ <string name="screen_zoom_summary_small" msgid="5867245310241621570">"小"</string>
+ <string name="screen_zoom_summary_default" msgid="2247006805614056507">"預設"</string>
+ <string name="screen_zoom_summary_large" msgid="4835294730065424084">"大"</string>
+ <string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"較大"</string>
+ <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"最大"</string>
+ <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"自訂 (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-zh-rTW/strings.xml b/packages/SettingsLib/res/values-zh-rTW/strings.xml
index dc029d9..9c85f0e 100644
--- a/packages/SettingsLib/res/values-zh-rTW/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rTW/strings.xml
@@ -316,4 +316,10 @@
<string name="home" msgid="8263346537524314127">"主畫面"</string>
<string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g>前"</string>
<string name="remaining_length_format" msgid="7886337596669190587">"還剩 <xliff:g id="ID_1">%1$s</xliff:g>"</string>
+ <string name="screen_zoom_summary_small" msgid="5867245310241621570">"小"</string>
+ <string name="screen_zoom_summary_default" msgid="2247006805614056507">"預設"</string>
+ <string name="screen_zoom_summary_large" msgid="4835294730065424084">"大"</string>
+ <string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"較大"</string>
+ <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"最大"</string>
+ <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"自訂 (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-zu/strings.xml b/packages/SettingsLib/res/values-zu/strings.xml
index 9ba957a..6017d68 100644
--- a/packages/SettingsLib/res/values-zu/strings.xml
+++ b/packages/SettingsLib/res/values-zu/strings.xml
@@ -316,4 +316,10 @@
<string name="home" msgid="8263346537524314127">"Ekhaya"</string>
<string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> edlule"</string>
<string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> osele"</string>
+ <string name="screen_zoom_summary_small" msgid="5867245310241621570">"Okuncane"</string>
+ <string name="screen_zoom_summary_default" msgid="2247006805614056507">"Okuzenzakalelayo"</string>
+ <string name="screen_zoom_summary_large" msgid="4835294730065424084">"Okukhulu"</string>
+ <string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"Okukhulu kakhulu"</string>
+ <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Okukhulu kakhulu"</string>
+ <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Ngokwezifiso (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
</resources>
diff --git a/core/java/com/android/internal/app/ProcessStats.aidl b/packages/SettingsLib/res/values/config.xml
old mode 100644
new mode 100755
similarity index 71%
copy from core/java/com/android/internal/app/ProcessStats.aidl
copy to packages/SettingsLib/res/values/config.xml
index 48b1f85..299a5b7
--- a/core/java/com/android/internal/app/ProcessStats.aidl
+++ b/packages/SettingsLib/res/values/config.xml
@@ -1,5 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
/*
-** Copyright 2013, The Android Open Source Project
+** 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.
@@ -13,7 +15,8 @@
** See the License for the specific language governing permissions and
** limitations under the License.
*/
-
-package com.android.internal.app;
-
-parcelable ProcessStats;
+-->
+<resources>
+ <!-- Configuration for automotive -->
+ <bool name="enable_pbap_pce_profile">false</bool>
+</resources>
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index fe3ef1a..a560e3c 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -733,25 +733,44 @@
<!-- [CHAR_LIMIT=40] Label for estimated remaining duration of battery charging/discharging -->
<string name="power_remaining_duration_only">Approx. <xliff:g id="time">%1$s</xliff:g> left</string>
+ <!-- [CHAR_LIMIT=40] Short label for estimated remaining duration of battery charging/discharging -->
+ <string name="power_remaining_duration_only_short"><xliff:g id="time">%1$s</xliff:g> left</string>
+
<!-- [CHAR_LIMIT=40] Label for battery level chart when discharging with duration -->
<string name="power_discharging_duration"><xliff:g id="level">%1$s</xliff:g>
- approx. <xliff:g id="time">%2$s</xliff:g> left</string>
+ <!-- [CHAR_LIMIT=40] Label for battery level chart when discharging with duration -->
+ <string name="power_discharging_duration_short"><xliff:g id="level">%1$s</xliff:g>
+ - <xliff:g id="time">%2$s</xliff:g> left</string>
+
<!-- [CHAR_LIMIT=40] Label for battery level chart when charging -->
<string name="power_charging"><xliff:g id="level">%1$s</xliff:g> -
<xliff:g id="state">%2$s</xliff:g></string>
<!-- [CHAR_LIMIT=40] Label for battery level chart when charging with duration -->
<string name="power_charging_duration"><xliff:g id="level">%1$s</xliff:g> -
<xliff:g id="time">%2$s</xliff:g> until full</string>
+ <!-- [CHAR_LIMIT=40] Short label for battery level chart when charging with duration -->
+ <string name="power_charging_duration_short"><xliff:g id="level">%1$s</xliff:g> -
+ <xliff:g id="time">%2$s</xliff:g></string>
<!-- [CHAR_LIMIT=40] Label for battery level chart when charging with duration -->
<string name="power_charging_duration_ac"><xliff:g id="level">%1$s</xliff:g> -
<xliff:g id="time">%2$s</xliff:g> until full on AC</string>
+ <!-- [CHAR_LIMIT=40] Short label for battery level chart when charging with duration -->
+ <string name="power_charging_duration_ac_short"><xliff:g id="level">%1$s</xliff:g> -
+ <xliff:g id="time">%2$s</xliff:g></string>
<!-- [CHAR_LIMIT=40] Label for battery level chart when charging with duration -->
<string name="power_charging_duration_usb"><xliff:g id="level">%1$s</xliff:g> -
<xliff:g id="time">%2$s</xliff:g> until full over USB</string>
+ <!-- [CHAR_LIMIT=40] Short label for battery level chart when charging with duration -->
+ <string name="power_charging_duration_usb_short"><xliff:g id="level">%1$s</xliff:g> -
+ <xliff:g id="time">%2$s</xliff:g></string>
<!-- [CHAR_LIMIT=40] Label for battery level chart when charging with duration -->
<string name="power_charging_duration_wireless"><xliff:g id="level">%1$s</xliff:g> -
<xliff:g id="time">%2$s</xliff:g> until full from wireless</string>
+ <!-- [CHAR_LIMIT=40] Label for battery level chart when charging with duration -->
+ <string name="power_charging_duration_wireless_short"><xliff:g id="level">%1$s</xliff:g> -
+ <xliff:g id="time">%2$s</xliff:g></string>
<!-- Battery Info screen. Value for a status item. Used for diagnostic info screens, precise translation isn't needed -->
<string name="battery_info_status_unknown">Unknown</string>
@@ -759,10 +778,16 @@
<string name="battery_info_status_charging">Charging</string>
<!-- [CHAR_LIMIT=20] Battery use screen. Battery status shown in chart label when charging on AC. -->
<string name="battery_info_status_charging_ac">Charging on AC</string>
+ <!-- [CHAR_LIMIT=20] Battery short status label when charing on AC -->
+ <string name="battery_info_status_charging_ac_short">Charging</string>
<!-- [CHAR_LIMIT=20] Battery use screen. Battery status shown in chart label when charging over USB. -->
<string name="battery_info_status_charging_usb">Charging over USB</string>
+ <!-- [CHAR_LIMIT=20] Battery short status label when charging over USB. -->
+ <string name="battery_info_status_charging_usb_short">Charging</string>
<!-- [CHAR_LIMIT=20] Battery use screen. Battery status shown in chart label when charging over a wireless connection. -->
<string name="battery_info_status_charging_wireless">Charging wirelessly</string>
+ <!-- [CHAR_LIMIT=20] Battery short status label when charging wirelessly. -->
+ <string name="battery_info_status_charging_wireless_short">Charging</string>
<!-- Battery Info screen. Value for a status item. Used for diagnostic info screens, precise translation isn't needed -->
<string name="battery_info_status_discharging">Not charging</string>
<!-- Battery Info screen. Value for a status item. Used for diagnostic info screens, precise translation isn't needed -->
diff --git a/packages/SettingsLib/src/com/android/settingslib/BatteryInfo.java b/packages/SettingsLib/src/com/android/settingslib/BatteryInfo.java
index 6b29e21..fa1f91f 100644
--- a/packages/SettingsLib/src/com/android/settingslib/BatteryInfo.java
+++ b/packages/SettingsLib/src/com/android/settingslib/BatteryInfo.java
@@ -25,6 +25,7 @@
import android.os.Bundle;
import android.os.SystemClock;
import android.text.format.Formatter;
+import android.util.Log;
import android.util.SparseIntArray;
import com.android.internal.os.BatteryStatsHelper;
import com.android.settingslib.graph.UsageView;
@@ -95,6 +96,11 @@
}
public static void getBatteryInfo(final Context context, final Callback callback) {
+ BatteryInfo.getBatteryInfo(context, callback, false);
+ }
+
+ public static void getBatteryInfo(final Context context, final Callback callback,
+ boolean shortString) {
new AsyncTask<Void, Void, BatteryStats>() {
@Override
protected BatteryStats doInBackground(Void... params) {
@@ -109,14 +115,20 @@
Intent batteryBroadcast = context.registerReceiver(null,
new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
BatteryInfo batteryInfo = BatteryInfo.getBatteryInfo(context,
- batteryBroadcast, batteryStats, elapsedRealtimeUs);
+ batteryBroadcast, batteryStats, elapsedRealtimeUs, shortString);
callback.onBatteryInfoLoaded(batteryInfo);
}
}.execute();
}
public static BatteryInfo getBatteryInfo(Context context, Intent batteryBroadcast,
- BatteryStats stats, long elapsedRealtimeUs) {
+ BatteryStats stats, long elapsedRealtimeUs) {
+ return BatteryInfo.getBatteryInfo(context, batteryBroadcast, stats, elapsedRealtimeUs,
+ false);
+ }
+
+ public static BatteryInfo getBatteryInfo(Context context, Intent batteryBroadcast,
+ BatteryStats stats, long elapsedRealtimeUs, boolean shortString) {
BatteryInfo info = new BatteryInfo();
info.mStats = stats;
info.mBatteryLevel = Utils.getBatteryLevel(batteryBroadcast);
@@ -129,9 +141,13 @@
info.remainingTimeUs = drainTime;
String timeString = Formatter.formatShortElapsedTime(context,
drainTime / 1000);
- info.remainingLabel = resources.getString(R.string.power_remaining_duration_only,
+ info.remainingLabel = resources.getString(
+ shortString ? R.string.power_remaining_duration_only_short
+ : R.string.power_remaining_duration_only,
timeString);
- info.mChargeLabelString = resources.getString(R.string.power_discharging_duration,
+ info.mChargeLabelString = resources.getString(
+ shortString ? R.string.power_discharging_duration_short
+ : R.string.power_discharging_duration,
info.batteryPercentString, timeString);
} else {
info.remainingLabel = null;
@@ -140,7 +156,7 @@
} else {
final long chargeTime = stats.computeChargeTimeRemaining(elapsedRealtimeUs);
final String statusLabel = Utils.getBatteryStatus(
- resources, batteryBroadcast);
+ resources, batteryBroadcast, shortString);
final int status = batteryBroadcast.getIntExtra(BatteryManager.EXTRA_STATUS,
BatteryManager.BATTERY_STATUS_UNKNOWN);
if (chargeTime > 0 && status != BatteryManager.BATTERY_STATUS_FULL) {
@@ -151,13 +167,17 @@
int plugType = batteryBroadcast.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0);
int resId;
if (plugType == BatteryManager.BATTERY_PLUGGED_AC) {
- resId = R.string.power_charging_duration_ac;
+ resId = shortString ? R.string.power_charging_duration_ac_short
+ : R.string.power_charging_duration_ac;
} else if (plugType == BatteryManager.BATTERY_PLUGGED_USB) {
- resId = R.string.power_charging_duration_usb;
+ resId = shortString ? R.string.power_charging_duration_usb_short
+ : R.string.power_charging_duration_usb;
} else if (plugType == BatteryManager.BATTERY_PLUGGED_WIRELESS) {
- resId = R.string.power_charging_duration_wireless;
+ resId = shortString ? R.string.power_charging_duration_wireless_short
+ : R.string.power_charging_duration_wireless;
} else {
- resId = R.string.power_charging_duration;
+ resId = shortString ? R.string.power_charging_duration_short
+ : R.string.power_charging_duration;
}
info.remainingLabel = resources.getString(R.string.power_remaining_duration_only,
timeString);
diff --git a/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtils.java b/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtils.java
index 1f1a9b8..e86ca82 100644
--- a/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtils.java
@@ -78,7 +78,8 @@
int deviceOwnerUserId = dpm.getDeviceOwnerUserId();
boolean enforcedByDeviceOwner = false;
if (deviceOwner != null && deviceOwnerUserId != UserHandle.USER_NULL) {
- Bundle enforcedRestrictions = dpm.getUserRestrictions(deviceOwner, deviceOwnerUserId);
+ Bundle enforcedRestrictions =
+ dpm.getUserRestrictionsForUser(deviceOwner, deviceOwnerUserId);
if (enforcedRestrictions != null
&& enforcedRestrictions.getBoolean(userRestriction, false)) {
enforcedByDeviceOwner = true;
@@ -90,7 +91,8 @@
if (userId != UserHandle.USER_NULL) {
profileOwner = dpm.getProfileOwnerAsUser(userId);
if (profileOwner != null) {
- Bundle enforcedRestrictions = dpm.getUserRestrictions(profileOwner, userId);
+ Bundle enforcedRestrictions =
+ dpm.getUserRestrictionsForUser(profileOwner, userId);
if (enforcedRestrictions != null
&& enforcedRestrictions.getBoolean(userRestriction, false)) {
enforcedByProfileOwner = true;
@@ -234,7 +236,7 @@
if (ipm.isPackageSuspendedForUser(packageName, userId)) {
return getProfileOrDeviceOwner(context, userId);
}
- } catch (RemoteException e) {
+ } catch (RemoteException | IllegalArgumentException e) {
// Nothing to do
}
return null;
diff --git a/packages/SettingsLib/src/com/android/settingslib/Utils.java b/packages/SettingsLib/src/com/android/settingslib/Utils.java
index 74c1ebd..586f269 100644
--- a/packages/SettingsLib/src/com/android/settingslib/Utils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/Utils.java
@@ -112,20 +112,26 @@
}
public static String getBatteryStatus(Resources res, Intent batteryChangedIntent) {
- final Intent intent = batteryChangedIntent;
+ return Utils.getBatteryStatus(res, batteryChangedIntent, false);
+ }
- int plugType = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0);
- int status = intent.getIntExtra(BatteryManager.EXTRA_STATUS,
+ public static String getBatteryStatus(Resources res, Intent batteryChangedIntent,
+ boolean shortString) {
+ int plugType = batteryChangedIntent.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0);
+ int status = batteryChangedIntent.getIntExtra(BatteryManager.EXTRA_STATUS,
BatteryManager.BATTERY_STATUS_UNKNOWN);
String statusString;
if (status == BatteryManager.BATTERY_STATUS_CHARGING) {
int resId;
if (plugType == BatteryManager.BATTERY_PLUGGED_AC) {
- resId = R.string.battery_info_status_charging_ac;
+ resId = shortString ? R.string.battery_info_status_charging_ac_short
+ : R.string.battery_info_status_charging_ac;
} else if (plugType == BatteryManager.BATTERY_PLUGGED_USB) {
- resId = R.string.battery_info_status_charging_usb;
+ resId = shortString ? R.string.battery_info_status_charging_usb_short
+ : R.string.battery_info_status_charging_usb;
} else if (plugType == BatteryManager.BATTERY_PLUGGED_WIRELESS) {
- resId = R.string.battery_info_status_charging_wireless;
+ resId = shortString ? R.string.battery_info_status_charging_wireless_short
+ : R.string.battery_info_status_charging_wireless;
} else {
resId = R.string.battery_info_status_charging;
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java
index 6226b23..6052ccd 100755
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java
@@ -24,12 +24,14 @@
import android.bluetooth.BluetoothMap;
import android.bluetooth.BluetoothInputDevice;
import android.bluetooth.BluetoothPan;
+import android.bluetooth.BluetoothPbapClient;
import android.bluetooth.BluetoothProfile;
import android.bluetooth.BluetoothUuid;
import android.content.Context;
import android.content.Intent;
import android.os.ParcelUuid;
import android.util.Log;
+import com.android.settingslib.R;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
@@ -82,7 +84,9 @@
private final HidProfile mHidProfile;
private OppProfile mOppProfile;
private final PanProfile mPanProfile;
+ private PbapClientProfile mPbapClientProfile;
private final PbapServerProfile mPbapProfile;
+ private final boolean mUsePbapPce;
/**
* Mapping from profile name, e.g. "HEADSET" to profile object.
@@ -99,6 +103,7 @@
mLocalAdapter = adapter;
mDeviceManager = deviceManager;
mEventManager = eventManager;
+ mUsePbapPce = mContext.getResources().getBoolean(R.bool.enable_pbap_pce_profile);
// pass this reference to adapter and event manager (circular dependency)
mLocalAdapter.setProfileManager(this);
mEventManager.setProfileManager(this);
@@ -205,9 +210,24 @@
} else if (mOppProfile != null) {
Log.w(TAG, "Warning: OPP profile was previously added but the UUID is now missing.");
}
+
+ //PBAP Client
+ if (mUsePbapPce) {
+ if (mPbapClientProfile == null) {
+ if(DEBUG) Log.d(TAG, "Adding local PBAP Client profile");
+ mPbapClientProfile = new PbapClientProfile(mContext, mLocalAdapter, mDeviceManager,
+ this);
+ addProfile(mPbapClientProfile, PbapClientProfile.NAME,
+ BluetoothPbapClient.ACTION_CONNECTION_STATE_CHANGED);
+ }
+ } else if (mPbapClientProfile != null) {
+ Log.w(TAG,
+ "Warning: PBAP Client profile was previously added but the UUID is now missing.");
+ }
+
mEventManager.registerProfileIntentReceiver();
- // There is no local SDP record for HID and Settings app doesn't control PBAP
+ // There is no local SDP record for HID and Settings app doesn't control PBAP Server.
}
private final Collection<ServiceListener> mServiceListeners =
@@ -351,6 +371,10 @@
}
}
+ public PbapClientProfile getPbapClientProfile() {
+ return mPbapClientProfile;
+ }
+
public PbapServerProfile getPbapProfile(){
return mPbapProfile;
}
@@ -430,6 +454,12 @@
removedProfiles.remove(mMapProfile);
mMapProfile.setPreferred(device, true);
}
- }
+ if (mUsePbapPce) {
+ profiles.add(mPbapClientProfile);
+ removedProfiles.remove(mPbapClientProfile);
+ profiles.remove(mPbapProfile);
+ removedProfiles.add(mPbapProfile);
+ }
+ }
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapClientProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapClientProfile.java
new file mode 100755
index 0000000..aa95be2
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapClientProfile.java
@@ -0,0 +1,233 @@
+/*
+ * 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.settingslib.bluetooth;
+
+import android.bluetooth.BluetoothPbapClient;
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothClass;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothProfile;
+import android.bluetooth.BluetoothUuid;
+import android.content.Context;
+import android.os.ParcelUuid;
+import android.util.Log;
+
+import com.android.settingslib.R;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+final class PbapClientProfile implements LocalBluetoothProfile {
+ private static final String TAG = "PbapClientProfile";
+ private static boolean V = false;
+
+ private BluetoothPbapClient mService;
+ private boolean mIsProfileReady;
+
+ private final LocalBluetoothAdapter mLocalAdapter;
+ private final CachedBluetoothDeviceManager mDeviceManager;
+
+ static final ParcelUuid[] SRC_UUIDS = {
+ BluetoothUuid.PBAP_PSE,
+ };
+
+ static final String NAME = "PbapClient";
+ private final LocalBluetoothProfileManager mProfileManager;
+
+ // Order of this profile in device profiles list
+ private static final int ORDINAL = 6;
+
+ // These callbacks run on the main thread.
+ private final class PbapClientServiceListener
+ implements BluetoothProfile.ServiceListener {
+
+ public void onServiceConnected(int profile, BluetoothProfile proxy) {
+ if (V) {
+ Log.d(TAG,"Bluetooth service connected");
+ }
+ mService = (BluetoothPbapClient) proxy;
+ // We just bound to the service, so refresh the UI for any connected PBAP devices.
+ List<BluetoothDevice> deviceList = mService.getConnectedDevices();
+ while (!deviceList.isEmpty()) {
+ BluetoothDevice nextDevice = deviceList.remove(0);
+ CachedBluetoothDevice device = mDeviceManager.findDevice(nextDevice);
+ // we may add a new device here, but generally this should not happen
+ if (device == null) {
+ Log.w(TAG, "PbapClientProfile found new device: " + nextDevice);
+ device = mDeviceManager.addDevice(mLocalAdapter, mProfileManager, nextDevice);
+ }
+ device.onProfileStateChanged(PbapClientProfile.this, BluetoothProfile.STATE_CONNECTED);
+ device.refresh();
+ }
+ mIsProfileReady = true;
+ }
+
+ public void onServiceDisconnected(int profile) {
+ if (V) {
+ Log.d(TAG,"Bluetooth service disconnected");
+ }
+ mIsProfileReady = false;
+ }
+ }
+
+ private void refreshProfiles() {
+ Collection<CachedBluetoothDevice> cachedDevices = mDeviceManager.getCachedDevicesCopy();
+ for (CachedBluetoothDevice device : cachedDevices) {
+ device.onUuidChanged();
+ }
+ }
+
+ public boolean pbapClientExists() {
+ return (mService != null);
+ }
+
+ public boolean isProfileReady() {
+ return mIsProfileReady;
+ }
+
+ PbapClientProfile(Context context, LocalBluetoothAdapter adapter,
+ CachedBluetoothDeviceManager deviceManager,
+ LocalBluetoothProfileManager profileManager) {
+ mLocalAdapter = adapter;
+ mDeviceManager = deviceManager;
+ mProfileManager = profileManager;
+ mLocalAdapter.getProfileProxy(context, new PbapClientServiceListener(),
+ BluetoothProfile.PBAP_CLIENT);
+ }
+
+ public boolean isConnectable() {
+ return true;
+ }
+
+ public boolean isAutoConnectable() {
+ return true;
+ }
+
+ public List<BluetoothDevice> getConnectedDevices() {
+ if (mService == null) {
+ return new ArrayList<BluetoothDevice>(0);
+ }
+ return mService.getDevicesMatchingConnectionStates(
+ new int[] {BluetoothProfile.STATE_CONNECTED,
+ BluetoothProfile.STATE_CONNECTING,
+ BluetoothProfile.STATE_DISCONNECTING});
+ }
+
+ public boolean connect(BluetoothDevice device) {
+ if (V) {
+ Log.d(TAG,"PBAPClientProfile got connect request");
+ }
+ if (mService == null) {
+ return false;
+ }
+ List<BluetoothDevice> srcs = getConnectedDevices();
+ if (srcs != null) {
+ for (BluetoothDevice src : srcs) {
+ if (src.equals(device)) {
+ // Connect to same device, Ignore it
+ Log.d(TAG,"Ignoring Connect");
+ return true;
+ }
+ }
+ mService.disconnect(device);
+ }
+ Log.d(TAG,"PBAPClientProfile attempting to connect to " + device.getAddress());
+
+ return mService.connect(device);
+ }
+
+ public boolean disconnect(BluetoothDevice device) {
+ if (V) {
+ Log.d(TAG,"PBAPClientProfile got disconnect request");
+ }
+ if (mService == null) {
+ return false;
+ }
+ return mService.disconnect(device);
+ }
+
+ public int getConnectionStatus(BluetoothDevice device) {
+ if (mService == null) {
+ return BluetoothProfile.STATE_DISCONNECTED;
+ }
+ return mService.getConnectionState(device);
+ }
+
+ public boolean isPreferred(BluetoothDevice device) {
+ if (mService == null) {
+ return false;
+ }
+ return mService.getPriority(device) > BluetoothProfile.PRIORITY_OFF;
+ }
+
+ public int getPreferred(BluetoothDevice device) {
+ if (mService == null) {
+ return BluetoothProfile.PRIORITY_OFF;
+ }
+ return mService.getPriority(device);
+ }
+
+ public void setPreferred(BluetoothDevice device, boolean preferred) {
+ if (mService == null) {
+ return;
+ }
+ if (preferred) {
+ if (mService.getPriority(device) < BluetoothProfile.PRIORITY_ON) {
+ mService.setPriority(device, BluetoothProfile.PRIORITY_ON);
+ }
+ } else {
+ mService.setPriority(device, BluetoothProfile.PRIORITY_OFF);
+ }
+ }
+
+ public String toString() {
+ return NAME;
+ }
+
+ public int getOrdinal() {
+ return ORDINAL;
+ }
+
+ public int getNameResource(BluetoothDevice device) {
+ // we need to have same string in UI as the server side.
+ return R.string.bluetooth_profile_pbap;
+ }
+
+ public int getSummaryResourceForDevice(BluetoothDevice device) {
+ return R.string.bluetooth_profile_pbap_summary;
+ }
+
+ public int getDrawableResource(BluetoothClass btClass) {
+ return R.drawable.ic_bt_cellphone;
+ }
+
+ protected void finalize() {
+ if (V) {
+ Log.d(TAG, "finalize()");
+ }
+ if (mService != null) {
+ try {
+ BluetoothAdapter.getDefaultAdapter().closeProfileProxy(
+ BluetoothProfile.PBAP_CLIENT,mService);
+ mService = null;
+ } catch (Throwable t) {
+ Log.w(TAG, "Error cleaning up PBAP Client proxy", t);
+ }
+ }
+ }
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerActivity.java b/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerActivity.java
index ce69c5a..ff70190 100644
--- a/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerActivity.java
+++ b/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerActivity.java
@@ -41,6 +41,7 @@
import android.widget.ListView;
import android.widget.Toolbar;
import com.android.settingslib.R;
+import com.android.settingslib.applications.InterestingConfigChanges;
import java.util.ArrayList;
import java.util.HashMap;
@@ -55,6 +56,7 @@
private static List<DashboardCategory> sDashboardCategories;
private static HashMap<Pair<String, String>, Tile> sTileCache;
+ private static InterestingConfigChanges sConfigTracker;
private final PackageReceiver mPackageReceiver = new PackageReceiver();
private final List<CategoryListener> mCategoryListeners = new ArrayList<>();
@@ -153,8 +155,10 @@
mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
updateDrawer();
} else {
- mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED);
- mDrawerLayout = null;
+ if (mDrawerLayout != null) {
+ mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED);
+ mDrawerLayout = null;
+ }
}
}
@@ -172,8 +176,11 @@
@Override
public void setContentView(@LayoutRes int layoutResID) {
- LayoutInflater.from(this).inflate(layoutResID,
- (ViewGroup) findViewById(R.id.content_frame));
+ final ViewGroup parent = (ViewGroup) findViewById(R.id.content_frame);
+ if (parent != null) {
+ parent.removeAllViews();
+ }
+ LayoutInflater.from(this).inflate(layoutResID, parent);
}
@Override
@@ -208,6 +215,7 @@
public List<DashboardCategory> getDashboardCategories() {
if (sDashboardCategories == null) {
sTileCache = new HashMap<>();
+ sConfigTracker = new InterestingConfigChanges();
sDashboardCategories = TileUtils.getCategories(this, sTileCache);
}
return sDashboardCategories;
@@ -267,6 +275,9 @@
private class CategoriesUpdater extends AsyncTask<Void, Void, List<DashboardCategory>> {
@Override
protected List<DashboardCategory> doInBackground(Void... params) {
+ if (sConfigTracker.applyNewConfig(getResources())) {
+ sTileCache.clear();
+ }
return TileUtils.getCategories(SettingsDrawerActivity.this, sTileCache);
}
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index 987b5ea..61c9f2b 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -21,6 +21,7 @@
import android.app.AppGlobals;
import android.app.backup.BackupManager;
import android.content.BroadcastReceiver;
+import android.content.ComponentName;
import android.content.ContentProvider;
import android.content.ContentValues;
import android.content.Context;
@@ -63,6 +64,7 @@
import com.android.internal.content.PackageMonitor;
import com.android.internal.os.BackgroundThread;
import com.android.providers.settings.SettingsState.Setting;
+import com.android.server.SystemConfig;
import java.io.File;
import java.io.FileDescriptor;
@@ -1940,7 +1942,7 @@
}
private final class UpgradeController {
- private static final int SETTINGS_VERSION = 125;
+ private static final int SETTINGS_VERSION = 126;
private final int mUserId;
@@ -2136,6 +2138,35 @@
currentVersion = 125;
}
+ if (currentVersion == 125) {
+ // Version 125: Allow OEMs to set the default VR service.
+ final SettingsState secureSettings = getSecureSettingsLocked(userId);
+
+ Setting currentSetting = secureSettings.getSettingLocked(
+ Settings.Secure.ENABLED_VR_LISTENERS);
+ if (currentSetting == null) {
+ ArraySet<ComponentName> l =
+ SystemConfig.getInstance().getDefaultVrComponents();
+
+ if (l != null && !l.isEmpty()) {
+ StringBuilder b = new StringBuilder();
+ boolean start = true;
+ for (ComponentName c : l) {
+ if (!start) {
+ b.append(':');
+ }
+ b.append(c.flattenToString());
+ start = false;
+ }
+ secureSettings.insertSettingLocked(
+ Settings.Secure.ENABLED_VR_LISTENERS, b.toString(),
+ SettingsState.SYSTEM_PACKAGE_NAME);
+ }
+
+ }
+ currentVersion = 126;
+ }
+
// vXXX: Add new settings above this point.
// Return the current version.
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index 0c35573..b557dc4 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -139,7 +139,7 @@
<activity
android:name=".BugreportWarningActivity"
- android:theme="@*android:style/Theme.Material.DayNight.Dialog.Alert"
+ android:theme="@android:style/Theme.Material.Light.Dialog.Alert"
android:finishOnCloseSystemDialogs="true"
android:excludeFromRecents="true"
android:exported="false" />
diff --git a/packages/SystemUI/res/anim/major_a_b_dot_01_animation.xml b/packages/SystemUI/res/anim/major_a_b_dot_01_animation.xml
new file mode 100644
index 0000000..b5bb4dc
--- /dev/null
+++ b/packages/SystemUI/res/anim/major_a_b_dot_01_animation.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2016 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<set
+ xmlns:android="http://schemas.android.com/apk/res/android" >
+ <objectAnimator
+ android:duration="250"
+ android:propertyXName="translateX"
+ android:propertyYName="translateY"
+ android:pathData="M 3.25,4.0 c 0.79167,0.0 3.95833,0.0 4.75,0.0"
+ android:interpolator="@android:interpolator/fast_out_slow_in" />
+</set>
diff --git a/packages/SystemUI/res/anim/major_a_b_dot_animation.xml b/packages/SystemUI/res/anim/major_a_b_dot_animation.xml
new file mode 100644
index 0000000..6443167
--- /dev/null
+++ b/packages/SystemUI/res/anim/major_a_b_dot_animation.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2016 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<set
+ xmlns:android="http://schemas.android.com/apk/res/android" >
+ <objectAnimator
+ android:duration="250"
+ android:propertyName="pathData"
+ android:valueFrom="M 0.0,-2.75 l 0.0,0.0 c 1.51878306195,0.0 2.75,1.23121693805 2.75,2.75 l 0.0,0.0 c 0.0,1.51878306195 -1.23121693805,2.75 -2.75,2.75 l 0.0,0.0 c -1.51878306195,0.0 -2.75,-1.23121693805 -2.75,-2.75 l 0.0,0.0 c 0.0,-1.51878306195 1.23121693805,-2.75 2.75,-2.75 Z"
+ android:valueTo="M -4.75,-2.75 l 9.5,0.0 c 1.51878306195,0.0 2.75,1.23121693805 2.75,2.75 l 0.0,0.0 c 0.0,1.51878306195 -1.23121693805,2.75 -2.75,2.75 l -9.5,0.0 c -1.51878306195,0.0 -2.75,-1.23121693805 -2.75,-2.75 l 0.0,0.0 c 0.0,-1.51878306195 1.23121693805,-2.75 2.75,-2.75 Z"
+ android:valueType="pathType"
+ android:interpolator="@android:interpolator/fast_out_slow_in" />
+</set>
diff --git a/packages/SystemUI/res/anim/major_b_a_dot_01_animation.xml b/packages/SystemUI/res/anim/major_b_a_dot_01_animation.xml
new file mode 100644
index 0000000..2e0a4fa
--- /dev/null
+++ b/packages/SystemUI/res/anim/major_b_a_dot_01_animation.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2016 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<set
+ xmlns:android="http://schemas.android.com/apk/res/android" >
+ <objectAnimator
+ android:duration="250"
+ android:propertyXName="translateX"
+ android:propertyYName="translateY"
+ android:pathData="M 8.0,4.0 c -0.79167,0.0 -3.95833,0.0 -4.75,0.0"
+ android:interpolator="@android:interpolator/fast_out_slow_in" />
+</set>
diff --git a/packages/SystemUI/res/anim/major_b_a_dot_animation.xml b/packages/SystemUI/res/anim/major_b_a_dot_animation.xml
new file mode 100644
index 0000000..731c87c
--- /dev/null
+++ b/packages/SystemUI/res/anim/major_b_a_dot_animation.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2016 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<set
+ xmlns:android="http://schemas.android.com/apk/res/android" >
+ <objectAnimator
+ android:duration="250"
+ android:propertyName="pathData"
+ android:valueFrom="M -4.75,-2.75 l 9.5,0.0 c 1.51878306195,0.0 2.75,1.23121693805 2.75,2.75 l 0.0,0.0 c 0.0,1.51878306195 -1.23121693805,2.75 -2.75,2.75 l -9.5,0.0 c -1.51878306195,0.0 -2.75,-1.23121693805 -2.75,-2.75 l 0.0,0.0 c 0.0,-1.51878306195 1.23121693805,-2.75 2.75,-2.75 Z"
+ android:valueTo="M 0.0,-2.75 l 0.0,0.0 c 1.51878306195,0.0 2.75,1.23121693805 2.75,2.75 l 0.0,0.0 c 0.0,1.51878306195 -1.23121693805,2.75 -2.75,2.75 l 0.0,0.0 c -1.51878306195,0.0 -2.75,-1.23121693805 -2.75,-2.75 l 0.0,0.0 c 0.0,-1.51878306195 1.23121693805,-2.75 2.75,-2.75 Z"
+ android:valueType="pathType"
+ android:interpolator="@android:interpolator/fast_out_slow_in" />
+</set>
diff --git a/packages/SystemUI/res/anim/major_b_c_dot_01_animation.xml b/packages/SystemUI/res/anim/major_b_c_dot_01_animation.xml
new file mode 100644
index 0000000..e8c2687
--- /dev/null
+++ b/packages/SystemUI/res/anim/major_b_c_dot_01_animation.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2016 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<set
+ xmlns:android="http://schemas.android.com/apk/res/android" >
+ <objectAnimator
+ android:duration="250"
+ android:propertyXName="translateX"
+ android:propertyYName="translateY"
+ android:pathData="M 8.0,4.0 c 0.79167,0.0 3.95833,0.0 4.75,0.0"
+ android:interpolator="@android:interpolator/fast_out_slow_in" />
+</set>
diff --git a/packages/SystemUI/res/anim/major_b_c_dot_animation.xml b/packages/SystemUI/res/anim/major_b_c_dot_animation.xml
new file mode 100644
index 0000000..731c87c
--- /dev/null
+++ b/packages/SystemUI/res/anim/major_b_c_dot_animation.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2016 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<set
+ xmlns:android="http://schemas.android.com/apk/res/android" >
+ <objectAnimator
+ android:duration="250"
+ android:propertyName="pathData"
+ android:valueFrom="M -4.75,-2.75 l 9.5,0.0 c 1.51878306195,0.0 2.75,1.23121693805 2.75,2.75 l 0.0,0.0 c 0.0,1.51878306195 -1.23121693805,2.75 -2.75,2.75 l -9.5,0.0 c -1.51878306195,0.0 -2.75,-1.23121693805 -2.75,-2.75 l 0.0,0.0 c 0.0,-1.51878306195 1.23121693805,-2.75 2.75,-2.75 Z"
+ android:valueTo="M 0.0,-2.75 l 0.0,0.0 c 1.51878306195,0.0 2.75,1.23121693805 2.75,2.75 l 0.0,0.0 c 0.0,1.51878306195 -1.23121693805,2.75 -2.75,2.75 l 0.0,0.0 c -1.51878306195,0.0 -2.75,-1.23121693805 -2.75,-2.75 l 0.0,0.0 c 0.0,-1.51878306195 1.23121693805,-2.75 2.75,-2.75 Z"
+ android:valueType="pathType"
+ android:interpolator="@android:interpolator/fast_out_slow_in" />
+</set>
diff --git a/packages/SystemUI/res/anim/major_c_b_dot_01_animation.xml b/packages/SystemUI/res/anim/major_c_b_dot_01_animation.xml
new file mode 100644
index 0000000..d0174bc
--- /dev/null
+++ b/packages/SystemUI/res/anim/major_c_b_dot_01_animation.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2016 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<set
+ xmlns:android="http://schemas.android.com/apk/res/android" >
+ <objectAnimator
+ android:duration="250"
+ android:propertyXName="translateX"
+ android:propertyYName="translateY"
+ android:pathData="M 12.75,4.0 c -0.79167,0.0 -3.95833,0.0 -4.75,0.0"
+ android:interpolator="@android:interpolator/fast_out_slow_in" />
+</set>
diff --git a/packages/SystemUI/res/anim/major_c_b_dot_animation.xml b/packages/SystemUI/res/anim/major_c_b_dot_animation.xml
new file mode 100644
index 0000000..6443167
--- /dev/null
+++ b/packages/SystemUI/res/anim/major_c_b_dot_animation.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2016 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<set
+ xmlns:android="http://schemas.android.com/apk/res/android" >
+ <objectAnimator
+ android:duration="250"
+ android:propertyName="pathData"
+ android:valueFrom="M 0.0,-2.75 l 0.0,0.0 c 1.51878306195,0.0 2.75,1.23121693805 2.75,2.75 l 0.0,0.0 c 0.0,1.51878306195 -1.23121693805,2.75 -2.75,2.75 l 0.0,0.0 c -1.51878306195,0.0 -2.75,-1.23121693805 -2.75,-2.75 l 0.0,0.0 c 0.0,-1.51878306195 1.23121693805,-2.75 2.75,-2.75 Z"
+ android:valueTo="M -4.75,-2.75 l 9.5,0.0 c 1.51878306195,0.0 2.75,1.23121693805 2.75,2.75 l 0.0,0.0 c 0.0,1.51878306195 -1.23121693805,2.75 -2.75,2.75 l -9.5,0.0 c -1.51878306195,0.0 -2.75,-1.23121693805 -2.75,-2.75 l 0.0,0.0 c 0.0,-1.51878306195 1.23121693805,-2.75 2.75,-2.75 Z"
+ android:valueType="pathType"
+ android:interpolator="@android:interpolator/fast_out_slow_in" />
+</set>
diff --git a/packages/SystemUI/res/anim/minor_a_b_dot_02_animation.xml b/packages/SystemUI/res/anim/minor_a_b_dot_02_animation.xml
new file mode 100644
index 0000000..b5bb4dc
--- /dev/null
+++ b/packages/SystemUI/res/anim/minor_a_b_dot_02_animation.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2016 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<set
+ xmlns:android="http://schemas.android.com/apk/res/android" >
+ <objectAnimator
+ android:duration="250"
+ android:propertyXName="translateX"
+ android:propertyYName="translateY"
+ android:pathData="M 3.25,4.0 c 0.79167,0.0 3.95833,0.0 4.75,0.0"
+ android:interpolator="@android:interpolator/fast_out_slow_in" />
+</set>
diff --git a/packages/SystemUI/res/anim/minor_b_a_dot_02_animation.xml b/packages/SystemUI/res/anim/minor_b_a_dot_02_animation.xml
new file mode 100644
index 0000000..2e0a4fa
--- /dev/null
+++ b/packages/SystemUI/res/anim/minor_b_a_dot_02_animation.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2016 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<set
+ xmlns:android="http://schemas.android.com/apk/res/android" >
+ <objectAnimator
+ android:duration="250"
+ android:propertyXName="translateX"
+ android:propertyYName="translateY"
+ android:pathData="M 8.0,4.0 c -0.79167,0.0 -3.95833,0.0 -4.75,0.0"
+ android:interpolator="@android:interpolator/fast_out_slow_in" />
+</set>
diff --git a/packages/SystemUI/res/anim/minor_b_c_dot_02_animation.xml b/packages/SystemUI/res/anim/minor_b_c_dot_02_animation.xml
new file mode 100644
index 0000000..e8c2687
--- /dev/null
+++ b/packages/SystemUI/res/anim/minor_b_c_dot_02_animation.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2016 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<set
+ xmlns:android="http://schemas.android.com/apk/res/android" >
+ <objectAnimator
+ android:duration="250"
+ android:propertyXName="translateX"
+ android:propertyYName="translateY"
+ android:pathData="M 8.0,4.0 c 0.79167,0.0 3.95833,0.0 4.75,0.0"
+ android:interpolator="@android:interpolator/fast_out_slow_in" />
+</set>
diff --git a/packages/SystemUI/res/anim/minor_c_b_dot_02_animation.xml b/packages/SystemUI/res/anim/minor_c_b_dot_02_animation.xml
new file mode 100644
index 0000000..d0174bc
--- /dev/null
+++ b/packages/SystemUI/res/anim/minor_c_b_dot_02_animation.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2016 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<set
+ xmlns:android="http://schemas.android.com/apk/res/android" >
+ <objectAnimator
+ android:duration="250"
+ android:propertyXName="translateX"
+ android:propertyYName="translateY"
+ android:pathData="M 12.75,4.0 c -0.79167,0.0 -3.95833,0.0 -4.75,0.0"
+ android:interpolator="@android:interpolator/fast_out_slow_in" />
+</set>
diff --git a/packages/SystemUI/res/anim/tv_pip_controls_fade_in.xml b/packages/SystemUI/res/anim/tv_pip_controls_buttons_in_recents_focus_gain_animation.xml
similarity index 78%
rename from packages/SystemUI/res/anim/tv_pip_controls_fade_in.xml
rename to packages/SystemUI/res/anim/tv_pip_controls_buttons_in_recents_focus_gain_animation.xml
index 89e4aac..ebc6a4a7 100644
--- a/packages/SystemUI/res/anim/tv_pip_controls_fade_in.xml
+++ b/packages/SystemUI/res/anim/tv_pip_controls_buttons_in_recents_focus_gain_animation.xml
@@ -17,13 +17,13 @@
<set xmlns:android="http://schemas.android.com/apk/res/android">
<objectAnimator
- android:propertyName="translationY"
- android:valueTo="10dp"
- android:interpolator="@android:interpolator/linear_out_slow_in"
+ android:propertyName="scaleX"
+ android:valueTo="1.0"
+ android:interpolator="@android:interpolator/fast_out_slow_in"
android:duration="@integer/recents_tv_pip_focus_anim_duration" />
<objectAnimator
- android:propertyName="alpha"
+ android:propertyName="scaleY"
android:valueTo="1.0"
- android:interpolator="@android:interpolator/linear_out_slow_in"
+ android:interpolator="@android:interpolator/fast_out_slow_in"
android:duration="@integer/recents_tv_pip_focus_anim_duration" />
</set>
diff --git a/packages/SystemUI/res/anim/tv_pip_controls_fade_out.xml b/packages/SystemUI/res/anim/tv_pip_controls_buttons_in_recents_focus_lose_animation.xml
similarity index 76%
rename from packages/SystemUI/res/anim/tv_pip_controls_fade_out.xml
rename to packages/SystemUI/res/anim/tv_pip_controls_buttons_in_recents_focus_lose_animation.xml
index c73fed6..95499bd 100644
--- a/packages/SystemUI/res/anim/tv_pip_controls_fade_out.xml
+++ b/packages/SystemUI/res/anim/tv_pip_controls_buttons_in_recents_focus_lose_animation.xml
@@ -17,13 +17,13 @@
<set xmlns:android="http://schemas.android.com/apk/res/android">
<objectAnimator
- android:propertyName="translationY"
- android:valueTo="0dp"
- android:interpolator="@android:interpolator/fast_out_linear_in"
+ android:propertyName="scaleX"
+ android:valueTo="0.7"
+ android:interpolator="@android:interpolator/fast_out_slow_in"
android:duration="@integer/recents_tv_pip_focus_anim_duration" />
<objectAnimator
- android:propertyName="alpha"
- android:valueTo="0.0"
- android:interpolator="@android:interpolator/fast_out_linear_in"
+ android:propertyName="scaleY"
+ android:valueTo="0.7"
+ android:interpolator="@android:interpolator/fast_out_slow_in"
android:duration="@integer/recents_tv_pip_focus_anim_duration" />
</set>
diff --git a/packages/SystemUI/res/anim/tv_pip_controls_in_recents_focus_gain_animation.xml b/packages/SystemUI/res/anim/tv_pip_controls_in_recents_focus_gain_animation.xml
new file mode 100644
index 0000000..7555bdd
--- /dev/null
+++ b/packages/SystemUI/res/anim/tv_pip_controls_in_recents_focus_gain_animation.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
+ android:propertyName="translationY"
+ android:valueTo="0dp"
+ android:interpolator="@android:interpolator/fast_out_slow_in"
+ android:duration="@integer/recents_tv_pip_focus_anim_duration" />
diff --git a/packages/SystemUI/res/anim/tv_pip_controls_in_recents_focus_lose_animation.xml b/packages/SystemUI/res/anim/tv_pip_controls_in_recents_focus_lose_animation.xml
new file mode 100644
index 0000000..b40ccd4
--- /dev/null
+++ b/packages/SystemUI/res/anim/tv_pip_controls_in_recents_focus_lose_animation.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
+ android:propertyName="translationY"
+ android:valueTo="-57dp"
+ android:interpolator="@android:interpolator/fast_out_slow_in"
+ android:duration="@integer/recents_tv_pip_focus_anim_duration" />
diff --git a/packages/SystemUI/res/anim/tv_pip_controls_text_in_recents_focus_gain_animation.xml b/packages/SystemUI/res/anim/tv_pip_controls_text_in_recents_focus_gain_animation.xml
new file mode 100644
index 0000000..681ff91
--- /dev/null
+++ b/packages/SystemUI/res/anim/tv_pip_controls_text_in_recents_focus_gain_animation.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
+ android:propertyName="alpha"
+ android:valueTo="1"
+ android:interpolator="@android:interpolator/fast_out_slow_in"
+ android:duration="@integer/recents_tv_pip_focus_anim_duration" />
diff --git a/packages/SystemUI/res/anim/tv_pip_controls_text_in_recents_focus_lose_animation.xml b/packages/SystemUI/res/anim/tv_pip_controls_text_in_recents_focus_lose_animation.xml
new file mode 100644
index 0000000..e6deb0f
--- /dev/null
+++ b/packages/SystemUI/res/anim/tv_pip_controls_text_in_recents_focus_lose_animation.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
+ android:propertyName="alpha"
+ android:valueTo="0"
+ android:interpolator="@android:interpolator/fast_out_slow_in"
+ android:duration="@integer/recents_tv_pip_focus_anim_duration" />
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_notify_image.png b/packages/SystemUI/res/drawable-hdpi/stat_notify_image.png
deleted file mode 100644
index 7b0fcc7..0000000
--- a/packages/SystemUI/res/drawable-hdpi/stat_notify_image.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_notify_image_error.png b/packages/SystemUI/res/drawable-hdpi/stat_notify_image_error.png
deleted file mode 100644
index 73e9c96..0000000
--- a/packages/SystemUI/res/drawable-hdpi/stat_notify_image_error.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_notify_image.png b/packages/SystemUI/res/drawable-mdpi/stat_notify_image.png
deleted file mode 100644
index a02e21c..0000000
--- a/packages/SystemUI/res/drawable-mdpi/stat_notify_image.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_notify_image_error.png b/packages/SystemUI/res/drawable-mdpi/stat_notify_image_error.png
deleted file mode 100644
index 4af2617..0000000
--- a/packages/SystemUI/res/drawable-mdpi/stat_notify_image_error.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_notify_image.png b/packages/SystemUI/res/drawable-xhdpi/stat_notify_image.png
deleted file mode 100644
index 24bdbb6..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/stat_notify_image.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_notify_image_error.png b/packages/SystemUI/res/drawable-xhdpi/stat_notify_image_error.png
deleted file mode 100644
index 6ecd2d3..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/stat_notify_image_error.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/stat_notify_image.png b/packages/SystemUI/res/drawable-xxhdpi/stat_notify_image.png
deleted file mode 100644
index 5e733ef..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/stat_notify_image.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/stat_notify_image_error.png b/packages/SystemUI/res/drawable-xxhdpi/stat_notify_image_error.png
deleted file mode 100644
index ecc2c83..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/stat_notify_image_error.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable/ic_data_saver.xml b/packages/SystemUI/res/drawable/ic_data_saver.xml
index 426238c..7356772 100644
--- a/packages/SystemUI/res/drawable/ic_data_saver.xml
+++ b/packages/SystemUI/res/drawable/ic_data_saver.xml
@@ -20,9 +20,11 @@
android:viewportHeight="24.0">
<path
android:fillColor="#FFFFFFFF"
- android:pathData="
- M9.0,16.0l2.0,0.0L11.0,8.0L9.0,8.0l0.0,8.0z
- m3.0,-14.0C6.48,2.0 2.0,6.48 2.0,12.0s4.48,10.0 10.0,10.0 10.0,-4.48 10.0,-10.0S17.52,2.0 12.0,2.0z
- m0.0,18.0c-4.41,0.0 -8.0,-3.59 -8.0,-8.0s3.59,-8.0 8.0,-8.0 8.0,3.59 8.0,8.0 -3.59,8.0 -8.0,8.0z
- m1.0,-4.0l2.0,0.0l0.0,-8.0l-2.0,0.0l0.0,8.0z"/>
+ android:pathData="M12.0,19.0c-3.9,0.0 -7.0,-3.1 -7.0,-7.0c0.0,-3.5 2.6,-6.4 6.0,-6.9L11.0,2.0C5.9,2.5 2.0,6.8 2.0,12.0c0.0,5.5 4.5,10.0 10.0,10.0c3.3,0.0 6.2,-1.6 8.1,-4.1l-2.6,-1.5C16.2,18.0 14.2,19.0 12.0,19.0z"/>
+ <path
+ android:fillColor="#4DFFFFFF"
+ android:pathData="M13.0,2.0l0.0,3.0c3.4,0.5 6.0,3.4 6.0,6.9c0.0,0.9 -0.2,1.8 -0.5,2.5l2.6,1.5c0.6,-1.2 0.9,-2.6 0.9,-4.1C22.0,6.8 18.0,2.6 13.0,2.0z"/>
+ <path
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M16.0,11.0l0.0,2.0 -3.0,0.0 0.0,3.0 -2.0,0.0 0.0,-3.0 -3.0,0.0 0.0,-2.0 3.0,0.0 0.0,-3.0 2.0,0.0 0.0,3.0z"/>
</vector>
diff --git a/packages/SystemUI/res/drawable/ic_data_saver_off.xml b/packages/SystemUI/res/drawable/ic_data_saver_off.xml
index 0713548..fd9701e 100644
--- a/packages/SystemUI/res/drawable/ic_data_saver_off.xml
+++ b/packages/SystemUI/res/drawable/ic_data_saver_off.xml
@@ -17,12 +17,12 @@
android:width="24.0dp"
android:height="24.0dp"
android:viewportWidth="24.0"
- android:viewportHeight="24.0">
+ android:viewportHeight="24.0"
+ android:tint="#4DFFFFFF">
<path
- android:fillColor="#4DFFFFFF"
- android:pathData="
- M9.0,16.0l2.0,0.0L11.0,8.0L9.0,8.0l0.0,8.0z
- m3.0,-14.0C6.48,2.0 2.0,6.48 2.0,12.0s4.48,10.0 10.0,10.0 10.0,-4.48 10.0,-10.0S17.52,2.0 12.0,2.0z
- m0.0,18.0c-4.41,0.0 -8.0,-3.59 -8.0,-8.0s3.59,-8.0 8.0,-8.0 8.0,3.59 8.0,8.0 -3.59,8.0 -8.0,8.0z
- m1.0,-4.0l2.0,0.0l0.0,-8.0l-2.0,0.0l0.0,8.0z"/>
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M12.0,19.0c-3.9,0.0 -7.0,-3.1 -7.0,-7.0c0.0,-3.5 2.6,-6.4 6.0,-6.9L11.0,2.0C5.9,2.5 2.0,6.8 2.0,12.0c0.0,5.5 4.5,10.0 10.0,10.0c3.3,0.0 6.2,-1.6 8.1,-4.1l-2.6,-1.5C16.2,18.0 14.2,19.0 12.0,19.0z"/>
+ <path
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M13.0,2.0l0.0,3.0c3.4,0.5 6.0,3.4 6.0,6.9c0.0,0.9 -0.2,1.8 -0.5,2.5l2.6,1.5c0.6,-1.2 0.9,-2.6 0.9,-4.1C22.0,6.8 18.0,2.6 13.0,2.0z"/>
</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_wifi_disconnected.xml b/packages/SystemUI/res/drawable/ic_qs_wifi_disconnected.xml
new file mode 100644
index 0000000..4d2a35e
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_qs_wifi_disconnected.xml
@@ -0,0 +1,45 @@
+<!--
+ Copyright (C) 2016 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="26.0dp"
+ android:height="24.0dp"
+ android:viewportWidth="26.0"
+ android:viewportHeight="24.0">
+ <path
+ android:pathData="M0 0h26v24H0z"
+ android:fillColor="#00000000"/>
+ <path
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M21.0,8.5
+ c0.85,0.0 1.6,0.23 2.3,0.62l2.24,-2.79
+ C25.1,5.96 20.26,2.0 13.0,2.0
+ S0.9,5.9 0.42,6.32
+ l12.57,15.6 4.21,-5.17
+ c-0.76,-0.87 -1.22,-2.0 -1.22,-3.25
+ c0.0,-2.76 2.24,-5.0 5.0,-5.0z"
+ android:fillAlpha=".3"/>
+ <path
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M21.0,10.0
+ c-1.93,0.0 -3.5,1.57 -3.5,3.5l1.75,0.0
+ c0.0,-0.9 0.78,-1.75 1.75,-1.75s1.7,0.78 1.75,1.75
+ c0.0,0.48 -0.2,0.92 -0.51,1.24l-1.09,1.1
+ c-0.6,0.63 -1.02,1.51 -1.02,2.47l0.0,0.44l1.75,0.0
+ c0.0,-1.3 0.39,-1.84 1.03,-2.47l0.78,-0.8
+ c0.5,-0.5 0.82,-1.2 0.82,-1.97
+ C24.5,11.57 22.93,10.0 21.0,10.0z
+ m-0.95,11.95l1.9,0.0l0.0,-1.9l-1.9,0.0l0.0,1.9z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/major_a_b.xml b/packages/SystemUI/res/drawable/major_a_b.xml
new file mode 100644
index 0000000..9900048
--- /dev/null
+++ b/packages/SystemUI/res/drawable/major_a_b.xml
@@ -0,0 +1,36 @@
+<?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.
+-->
+<vector
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:name="major_a_b"
+ android:width="16dp"
+ android:viewportWidth="16"
+ android:height="8dp"
+ android:viewportHeight="8" >
+ <group
+ android:name="dot_01"
+ android:translateX="3.25"
+ android:translateY="4" >
+ <group
+ android:name="dot_group" >
+ <path
+ android:name="dot"
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M 0.0,-2.75 l 0.0,0.0 c 1.51878306195,0.0 2.75,1.23121693805 2.75,2.75 l 0.0,0.0 c 0.0,1.51878306195 -1.23121693805,2.75 -2.75,2.75 l 0.0,0.0 c -1.51878306195,0.0 -2.75,-1.23121693805 -2.75,-2.75 l 0.0,0.0 c 0.0,-1.51878306195 1.23121693805,-2.75 2.75,-2.75 Z" />
+ </group>
+ </group>
+</vector>
diff --git a/packages/SystemUI/res/drawable/major_a_b_animation.xml b/packages/SystemUI/res/drawable/major_a_b_animation.xml
new file mode 100644
index 0000000..74d7544
--- /dev/null
+++ b/packages/SystemUI/res/drawable/major_a_b_animation.xml
@@ -0,0 +1,26 @@
+<?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.
+-->
+<animated-vector
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:drawable="@drawable/major_a_b" >
+ <target
+ android:name="dot_01"
+ android:animation="@anim/major_a_b_dot_01_animation" />
+ <target
+ android:name="dot"
+ android:animation="@anim/major_a_b_dot_animation" />
+</animated-vector>
diff --git a/packages/SystemUI/res/drawable/major_b_a.xml b/packages/SystemUI/res/drawable/major_b_a.xml
new file mode 100644
index 0000000..3115887
--- /dev/null
+++ b/packages/SystemUI/res/drawable/major_b_a.xml
@@ -0,0 +1,36 @@
+<?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.
+-->
+<vector
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:name="major_b_a"
+ android:width="16dp"
+ android:viewportWidth="16"
+ android:height="8dp"
+ android:viewportHeight="8" >
+ <group
+ android:name="dot_01"
+ android:translateX="8"
+ android:translateY="4" >
+ <group
+ android:name="dot_group" >
+ <path
+ android:name="dot"
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M -4.75,-2.75 l 9.5,0.0 c 1.51878306195,0.0 2.75,1.23121693805 2.75,2.75 l 0.0,0.0 c 0.0,1.51878306195 -1.23121693805,2.75 -2.75,2.75 l -9.5,0.0 c -1.51878306195,0.0 -2.75,-1.23121693805 -2.75,-2.75 l 0.0,0.0 c 0.0,-1.51878306195 1.23121693805,-2.75 2.75,-2.75 Z" />
+ </group>
+ </group>
+</vector>
diff --git a/packages/SystemUI/res/drawable/major_b_a_animation.xml b/packages/SystemUI/res/drawable/major_b_a_animation.xml
new file mode 100644
index 0000000..cf446e6
--- /dev/null
+++ b/packages/SystemUI/res/drawable/major_b_a_animation.xml
@@ -0,0 +1,26 @@
+<?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.
+-->
+<animated-vector
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:drawable="@drawable/major_b_a" >
+ <target
+ android:name="dot_01"
+ android:animation="@anim/major_b_a_dot_01_animation" />
+ <target
+ android:name="dot"
+ android:animation="@anim/major_b_a_dot_animation" />
+</animated-vector>
diff --git a/packages/SystemUI/res/drawable/major_b_c.xml b/packages/SystemUI/res/drawable/major_b_c.xml
new file mode 100644
index 0000000..899109e
--- /dev/null
+++ b/packages/SystemUI/res/drawable/major_b_c.xml
@@ -0,0 +1,36 @@
+<?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.
+-->
+<vector
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:name="major_b_c"
+ android:width="16dp"
+ android:viewportWidth="16"
+ android:height="8dp"
+ android:viewportHeight="8" >
+ <group
+ android:name="dot_01"
+ android:translateX="8"
+ android:translateY="4" >
+ <group
+ android:name="dot_group" >
+ <path
+ android:name="dot"
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M -4.75,-2.75 l 9.5,0.0 c 1.51878306195,0.0 2.75,1.23121693805 2.75,2.75 l 0.0,0.0 c 0.0,1.51878306195 -1.23121693805,2.75 -2.75,2.75 l -9.5,0.0 c -1.51878306195,0.0 -2.75,-1.23121693805 -2.75,-2.75 l 0.0,0.0 c 0.0,-1.51878306195 1.23121693805,-2.75 2.75,-2.75 Z" />
+ </group>
+ </group>
+</vector>
diff --git a/packages/SystemUI/res/drawable/major_b_c_animation.xml b/packages/SystemUI/res/drawable/major_b_c_animation.xml
new file mode 100644
index 0000000..38e12f4
--- /dev/null
+++ b/packages/SystemUI/res/drawable/major_b_c_animation.xml
@@ -0,0 +1,26 @@
+<?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.
+-->
+<animated-vector
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:drawable="@drawable/major_b_c" >
+ <target
+ android:name="dot_01"
+ android:animation="@anim/major_b_c_dot_01_animation" />
+ <target
+ android:name="dot"
+ android:animation="@anim/major_b_c_dot_animation" />
+</animated-vector>
diff --git a/packages/SystemUI/res/drawable/major_c_b.xml b/packages/SystemUI/res/drawable/major_c_b.xml
new file mode 100644
index 0000000..cc6c615
--- /dev/null
+++ b/packages/SystemUI/res/drawable/major_c_b.xml
@@ -0,0 +1,36 @@
+<?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.
+-->
+<vector
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:name="major_c_b"
+ android:width="16dp"
+ android:viewportWidth="16"
+ android:height="8dp"
+ android:viewportHeight="8" >
+ <group
+ android:name="dot_01"
+ android:translateX="12.75"
+ android:translateY="4" >
+ <group
+ android:name="dot_group" >
+ <path
+ android:name="dot"
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M 0.0,-2.75 l 0.0,0.0 c 1.51878306195,0.0 2.75,1.23121693805 2.75,2.75 l 0.0,0.0 c 0.0,1.51878306195 -1.23121693805,2.75 -2.75,2.75 l 0.0,0.0 c -1.51878306195,0.0 -2.75,-1.23121693805 -2.75,-2.75 l 0.0,0.0 c 0.0,-1.51878306195 1.23121693805,-2.75 2.75,-2.75 Z" />
+ </group>
+ </group>
+</vector>
diff --git a/packages/SystemUI/res/drawable/major_c_b_animation.xml b/packages/SystemUI/res/drawable/major_c_b_animation.xml
new file mode 100644
index 0000000..7f7850d
--- /dev/null
+++ b/packages/SystemUI/res/drawable/major_c_b_animation.xml
@@ -0,0 +1,26 @@
+<?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.
+-->
+<animated-vector
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:drawable="@drawable/major_c_b" >
+ <target
+ android:name="dot_01"
+ android:animation="@anim/major_c_b_dot_01_animation" />
+ <target
+ android:name="dot"
+ android:animation="@anim/major_c_b_dot_animation" />
+</animated-vector>
diff --git a/packages/SystemUI/res/drawable/minor_a_b.xml b/packages/SystemUI/res/drawable/minor_a_b.xml
new file mode 100644
index 0000000..c5f5c98
--- /dev/null
+++ b/packages/SystemUI/res/drawable/minor_a_b.xml
@@ -0,0 +1,37 @@
+<?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.
+-->
+<vector
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:name="minor_a_b"
+ android:alpha="0.3"
+ android:width="16dp"
+ android:viewportWidth="16"
+ android:height="8dp"
+ android:viewportHeight="8" >
+ <group
+ android:name="dot_02"
+ android:translateX="3.25"
+ android:translateY="4" >
+ <group
+ android:name="dot_group" >
+ <path
+ android:name="dot"
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M 0.0,-2.75 l 0.0,0.0 c 1.51878306195,0.0 2.75,1.23121693805 2.75,2.75 l 0.0,0.0 c 0.0,1.51878306195 -1.23121693805,2.75 -2.75,2.75 l 0.0,0.0 c -1.51878306195,0.0 -2.75,-1.23121693805 -2.75,-2.75 l 0.0,0.0 c 0.0,-1.51878306195 1.23121693805,-2.75 2.75,-2.75 Z" />
+ </group>
+ </group>
+</vector>
diff --git a/packages/SystemUI/res/drawable/minor_a_b_animation.xml b/packages/SystemUI/res/drawable/minor_a_b_animation.xml
new file mode 100644
index 0000000..50e20e7
--- /dev/null
+++ b/packages/SystemUI/res/drawable/minor_a_b_animation.xml
@@ -0,0 +1,23 @@
+<?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.
+-->
+<animated-vector
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:drawable="@drawable/minor_a_b" >
+ <target
+ android:name="dot_02"
+ android:animation="@anim/minor_a_b_dot_02_animation" />
+</animated-vector>
diff --git a/packages/SystemUI/res/drawable/minor_b_a.xml b/packages/SystemUI/res/drawable/minor_b_a.xml
new file mode 100644
index 0000000..3bb08c4
--- /dev/null
+++ b/packages/SystemUI/res/drawable/minor_b_a.xml
@@ -0,0 +1,37 @@
+<?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.
+-->
+<vector
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:name="minor_b_a"
+ android:alpha="0.3"
+ android:width="16dp"
+ android:viewportWidth="16"
+ android:height="8dp"
+ android:viewportHeight="8" >
+ <group
+ android:name="dot_02"
+ android:translateX="8"
+ android:translateY="4" >
+ <group
+ android:name="dot_group" >
+ <path
+ android:name="dot"
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M 0.0,-2.75 l 0.0,0.0 c 1.51878306195,0.0 2.75,1.23121693805 2.75,2.75 l 0.0,0.0 c 0.0,1.51878306195 -1.23121693805,2.75 -2.75,2.75 l 0.0,0.0 c -1.51878306195,0.0 -2.75,-1.23121693805 -2.75,-2.75 l 0.0,0.0 c 0.0,-1.51878306195 1.23121693805,-2.75 2.75,-2.75 Z" />
+ </group>
+ </group>
+</vector>
diff --git a/packages/SystemUI/res/drawable/minor_b_a_animation.xml b/packages/SystemUI/res/drawable/minor_b_a_animation.xml
new file mode 100644
index 0000000..460a2f7
--- /dev/null
+++ b/packages/SystemUI/res/drawable/minor_b_a_animation.xml
@@ -0,0 +1,23 @@
+<?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.
+-->
+<animated-vector
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:drawable="@drawable/minor_b_a" >
+ <target
+ android:name="dot_02"
+ android:animation="@anim/minor_b_a_dot_02_animation" />
+</animated-vector>
diff --git a/packages/SystemUI/res/drawable/minor_b_c.xml b/packages/SystemUI/res/drawable/minor_b_c.xml
new file mode 100644
index 0000000..95c6463
--- /dev/null
+++ b/packages/SystemUI/res/drawable/minor_b_c.xml
@@ -0,0 +1,37 @@
+<?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.
+-->
+<vector
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:name="minor_b_c"
+ android:alpha="0.3"
+ android:width="16dp"
+ android:viewportWidth="16"
+ android:height="8dp"
+ android:viewportHeight="8" >
+ <group
+ android:name="dot_02"
+ android:translateX="8"
+ android:translateY="4" >
+ <group
+ android:name="dot_group" >
+ <path
+ android:name="dot"
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M 0.0,-2.75 l 0.0,0.0 c 1.51878306195,0.0 2.75,1.23121693805 2.75,2.75 l 0.0,0.0 c 0.0,1.51878306195 -1.23121693805,2.75 -2.75,2.75 l 0.0,0.0 c -1.51878306195,0.0 -2.75,-1.23121693805 -2.75,-2.75 l 0.0,0.0 c 0.0,-1.51878306195 1.23121693805,-2.75 2.75,-2.75 Z" />
+ </group>
+ </group>
+</vector>
diff --git a/packages/SystemUI/res/drawable/minor_b_c_animation.xml b/packages/SystemUI/res/drawable/minor_b_c_animation.xml
new file mode 100644
index 0000000..53b8bd6
--- /dev/null
+++ b/packages/SystemUI/res/drawable/minor_b_c_animation.xml
@@ -0,0 +1,23 @@
+<?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.
+-->
+<animated-vector
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:drawable="@drawable/minor_b_c" >
+ <target
+ android:name="dot_02"
+ android:animation="@anim/minor_b_c_dot_02_animation" />
+</animated-vector>
diff --git a/packages/SystemUI/res/drawable/minor_c_b.xml b/packages/SystemUI/res/drawable/minor_c_b.xml
new file mode 100644
index 0000000..523afaa
--- /dev/null
+++ b/packages/SystemUI/res/drawable/minor_c_b.xml
@@ -0,0 +1,37 @@
+<?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.
+-->
+<vector
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:name="minor_c_b"
+ android:alpha="0.3"
+ android:width="16dp"
+ android:viewportWidth="16"
+ android:height="8dp"
+ android:viewportHeight="8" >
+ <group
+ android:name="dot_02"
+ android:translateX="12.75"
+ android:translateY="4" >
+ <group
+ android:name="dot_group" >
+ <path
+ android:name="dot"
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M 0.0,-2.75 l 0.0,0.0 c 1.51878306195,0.0 2.75,1.23121693805 2.75,2.75 l 0.0,0.0 c 0.0,1.51878306195 -1.23121693805,2.75 -2.75,2.75 l 0.0,0.0 c -1.51878306195,0.0 -2.75,-1.23121693805 -2.75,-2.75 l 0.0,0.0 c 0.0,-1.51878306195 1.23121693805,-2.75 2.75,-2.75 Z" />
+ </group>
+ </group>
+</vector>
diff --git a/packages/SystemUI/res/drawable/minor_c_b_animation.xml b/packages/SystemUI/res/drawable/minor_c_b_animation.xml
new file mode 100644
index 0000000..bf5e81e
--- /dev/null
+++ b/packages/SystemUI/res/drawable/minor_c_b_animation.xml
@@ -0,0 +1,23 @@
+<?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.
+-->
+<animated-vector
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:drawable="@drawable/minor_c_b" >
+ <target
+ android:name="dot_02"
+ android:animation="@anim/minor_c_b_dot_02_animation" />
+</animated-vector>
diff --git a/packages/SystemUI/res/drawable/stat_notify_image.xml b/packages/SystemUI/res/drawable/stat_notify_image.xml
new file mode 100644
index 0000000..c8745d7
--- /dev/null
+++ b/packages/SystemUI/res/drawable/stat_notify_image.xml
@@ -0,0 +1,28 @@
+<!--
+Copyright (C) 2016 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+
+ <path
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M21,19V5c0-1.1-0.9-2-2-2H5C3.9,3,3,3.9,3,5v14c0,1.1,0.9,2,2,2h14C20.1,21,21,20.1,21,19z
+M8.5,13.5l2.5,3l3.5-4.5l4.5,6H5 L8.5,13.5z" />
+ <path
+ android:pathData="M0,0h24v24H0V0z" />
+</vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/stat_notify_image_error.xml b/packages/SystemUI/res/drawable/stat_notify_image_error.xml
new file mode 100644
index 0000000..b929005
--- /dev/null
+++ b/packages/SystemUI/res/drawable/stat_notify_image_error.xml
@@ -0,0 +1,30 @@
+<!--
+Copyright (C) 2016 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+
+ <path
+ android:pathData="M0,0h24v24H0V0z" />
+ <path
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M17,18H5l3.5-4.5l2.5,3l3.3-4.5l2.7,3.8V8h4V5c0-1.1-0.9-2-2-2H5C3.9,3,3,3.9,3,5v14c0,1.1,0.9,2,2,2h12V18z" />
+ <path
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M19.2,21H21v-1.8h-1.8V21z M19.2,9.9v7.4H21V9.9H19.2z" />
+</vector>
diff --git a/packages/SystemUI/res/drawable/stat_sys_data_saver.xml b/packages/SystemUI/res/drawable/stat_sys_data_saver.xml
index a45f9a2..c36678d 100644
--- a/packages/SystemUI/res/drawable/stat_sys_data_saver.xml
+++ b/packages/SystemUI/res/drawable/stat_sys_data_saver.xml
@@ -23,10 +23,12 @@
android:viewportHeight="24.0">
<path
android:fillColor="#FFFFFFFF"
- android:pathData="
- M9.0,16.0l2.0,0.0L11.0,8.0L9.0,8.0l0.0,8.0z
- m3.0,-14.0C6.48,2.0 2.0,6.48 2.0,12.0s4.48,10.0 10.0,10.0 10.0,-4.48 10.0,-10.0S17.52,2.0 12.0,2.0z
- m0.0,18.0c-4.41,0.0 -8.0,-3.59 -8.0,-8.0s3.59,-8.0 8.0,-8.0 8.0,3.59 8.0,8.0 -3.59,8.0 -8.0,8.0z
- m1.0,-4.0l2.0,0.0l0.0,-8.0l-2.0,0.0l0.0,8.0z"/>
+ android:pathData="M12.0,19.0c-3.9,0.0 -7.0,-3.1 -7.0,-7.0c0.0,-3.5 2.6,-6.4 6.0,-6.9L11.0,2.0C5.9,2.5 2.0,6.8 2.0,12.0c0.0,5.5 4.5,10.0 10.0,10.0c3.3,0.0 6.2,-1.6 8.1,-4.1l-2.6,-1.5C16.2,18.0 14.2,19.0 12.0,19.0z"/>
+ <path
+ android:fillColor="#4DFFFFFF"
+ android:pathData="M13.0,2.0l0.0,3.0c3.4,0.5 6.0,3.4 6.0,6.9c0.0,0.9 -0.2,1.8 -0.5,2.5l2.6,1.5c0.6,-1.2 0.9,-2.6 0.9,-4.1C22.0,6.8 18.0,2.6 13.0,2.0z"/>
+ <path
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M16.0,11.0l0.0,2.0 -3.0,0.0 0.0,3.0 -2.0,0.0 0.0,-3.0 -3.0,0.0 0.0,-2.0 3.0,0.0 0.0,-3.0 2.0,0.0 0.0,3.0z"/>
</vector>
</inset>
diff --git a/packages/SystemUI/res/drawable/tv_pip_button_focused.xml b/packages/SystemUI/res/drawable/tv_pip_button_focused.xml
index 5cabb77..405ea0c 100644
--- a/packages/SystemUI/res/drawable/tv_pip_button_focused.xml
+++ b/packages/SystemUI/res/drawable/tv_pip_button_focused.xml
@@ -17,8 +17,8 @@
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<size
- android:width="36dp"
- android:height="36dp" />
+ android:width="34dp"
+ android:height="34dp" />
<solid
android:color="#4DFFFFFF" />
</shape>
diff --git a/packages/SystemUI/res/layout/keyboard_shortcuts_category_title.xml b/packages/SystemUI/res/layout/keyboard_shortcuts_category_title.xml
index 6cb8470..381fb16 100644
--- a/packages/SystemUI/res/layout/keyboard_shortcuts_category_title.xml
+++ b/packages/SystemUI/res/layout/keyboard_shortcuts_category_title.xml
@@ -16,7 +16,7 @@
~ limitations under the License
-->
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
+ android:layout_width="wrap_content"
android:layout_height="match_parent"
android:textSize="14sp"
android:paddingStart="24dp"
diff --git a/packages/SystemUI/res/layout/qs_customize_panel_content.xml b/packages/SystemUI/res/layout/qs_customize_panel_content.xml
index 75f8fa4..6438564 100644
--- a/packages/SystemUI/res/layout/qs_customize_panel_content.xml
+++ b/packages/SystemUI/res/layout/qs_customize_panel_content.xml
@@ -31,7 +31,8 @@
android:layout_height="0dp"
android:layout_weight="1"
android:scrollIndicators="top"
- android:scrollbars="vertical" />
+ android:scrollbars="vertical"
+ android:importantForAccessibility="no" />
<View
android:layout_width="match_parent"
diff --git a/core/res/res/layout/notification_action_list.xml b/packages/SystemUI/res/layout/qs_customize_tile_divider.xml
similarity index 65%
rename from core/res/res/layout/notification_action_list.xml
rename to packages/SystemUI/res/layout/qs_customize_tile_divider.xml
index 400decc..0d932ac 100644
--- a/core/res/res/layout/notification_action_list.xml
+++ b/packages/SystemUI/res/layout/qs_customize_tile_divider.xml
@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2012 The Android Open Source Project
+<!--
+ Copyright (C) 2016 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -14,17 +15,11 @@
limitations under the License.
-->
-<LinearLayout
+<View
xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/actions"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:orientation="horizontal"
- android:visibility="gone"
- android:layout_marginBottom="8dp"
- android:showDividers="middle"
- android:divider="?android:attr/listDivider"
- android:dividerPadding="12dp"
- >
- <!-- actions will be added here -->
-</LinearLayout>
+ android:layout_marginStart="16dp"
+ android:layout_marginEnd="16dp"
+ android:background="?android:attr/listDivider"
+ android:importantForAccessibility="no" />
diff --git a/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml b/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml
index cb861ec..b88846b 100644
--- a/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml
+++ b/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml
@@ -26,9 +26,6 @@
android:clipChildren="false"
android:clipToPadding="false"
android:baselineAligned="false"
- android:background="@drawable/quick_header_bg"
- android:clickable="true"
- android:focusable="true"
>
<LinearLayout
@@ -83,6 +80,10 @@
android:id="@+id/expand_indicator"
android:layout_width="48dp"
android:layout_height="48dp"
+ android:clipToPadding="false"
+ android:clickable="true"
+ android:focusable="true"
+ android:background="?android:attr/selectableItemBackgroundBorderless"
android:padding="12dp" />
</LinearLayout>
diff --git a/packages/SystemUI/res/layout/recents_on_tv.xml b/packages/SystemUI/res/layout/recents_on_tv.xml
index 0f8c77c..28ea66d 100644
--- a/packages/SystemUI/res/layout/recents_on_tv.xml
+++ b/packages/SystemUI/res/layout/recents_on_tv.xml
@@ -31,18 +31,12 @@
android:focusable="true"
android:layoutDirection="rtl" />
+ <!-- Placeholder view to give focus to the PIP menus. -->
<View
- android:id="@+id/pip_shade"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:visibility="gone"
- android:background="#76000000" />
-
- <include
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="top|center_horizontal"
- android:layout_marginTop="132dp"
- layout="@layout/tv_pip_controls" />
+ android:id="@+id/pip"
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ android:focusable="true"
+ android:visibility="gone" />
</com.android.systemui.recents.tv.views.RecentsTvView>
diff --git a/packages/SystemUI/res/layout/recents_stack_action_button.xml b/packages/SystemUI/res/layout/recents_stack_action_button.xml
index 8783261..625e9c1 100644
--- a/packages/SystemUI/res/layout/recents_stack_action_button.xml
+++ b/packages/SystemUI/res/layout/recents_stack_action_button.xml
@@ -18,7 +18,6 @@
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:gravity="start|center_vertical"
android:paddingStart="14dp"
android:paddingEnd="14dp"
android:paddingTop="12dp"
@@ -27,8 +26,6 @@
android:textSize="14sp"
android:textColor="#FFFFFF"
android:textAllCaps="true"
- android:drawableStart="@drawable/ic_history"
- android:drawablePadding="6dp"
android:shadowColor="#99000000"
android:shadowDx="0"
android:shadowDy="2"
diff --git a/packages/SystemUI/res/layout/tv_pip_controls.xml b/packages/SystemUI/res/layout/tv_pip_controls.xml
index 2e0c9e7..563441f 100644
--- a/packages/SystemUI/res/layout/tv_pip_controls.xml
+++ b/packages/SystemUI/res/layout/tv_pip_controls.xml
@@ -17,13 +17,8 @@
*/
-->
-<com.android.systemui.tv.pip.PipControlsView
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/pip_controls"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:gravity="center"
- android:orientation="horizontal">
+<!-- Layout for {@link com.android.systemui.tv.pip.PipControlsView}. -->
+<merge xmlns:android="http://schemas.android.com/apk/res/android">
<LinearLayout
android:layout_width="100dp"
@@ -98,4 +93,4 @@
android:textSize="12sp"
android:textColor="#EEEEEE" />
</LinearLayout>
-</com.android.systemui.tv.pip.PipControlsView>
+</merge>
diff --git a/packages/SystemUI/res/layout/tv_pip_menu.xml b/packages/SystemUI/res/layout/tv_pip_menu.xml
index c2c83ff..2647a99 100644
--- a/packages/SystemUI/res/layout/tv_pip_menu.xml
+++ b/packages/SystemUI/res/layout/tv_pip_menu.xml
@@ -26,7 +26,8 @@
android:gravity="top|center_horizontal"
android:clipChildren="false">
- <include
- layout="@layout/tv_pip_controls"
- android:clipChildren="false" />
+ <com.android.systemui.tv.pip.PipControlsView
+ android:id="@+id/pip_controls"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content" />
</LinearLayout>
diff --git a/packages/SystemUI/res/layout/tv_pip_overlay.xml b/packages/SystemUI/res/layout/tv_pip_overlay.xml
index c5c7e84..64bf3b5 100644
--- a/packages/SystemUI/res/layout/tv_pip_overlay.xml
+++ b/packages/SystemUI/res/layout/tv_pip_overlay.xml
@@ -38,25 +38,4 @@
android:gravity="center"
android:maxLines="2"
android:text="@string/pip_hold_home" />
- <LinearLayout
- android:id="@+id/guide_buttons"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_alignParentBottom="true"
- android:layout_centerHorizontal="true"
- android:orientation="horizontal">
- <ImageView
- android:layout_width="19dp"
- android:layout_height="19dp"
- android:src="@drawable/ic_fullscreen_white_24dp" />
- <ImageView
- android:layout_width="19dp"
- android:layout_height="19dp"
- android:src="@drawable/ic_close_white" />
- <ImageView
- android:id="@+id/guide_button_play_pause"
- android:layout_width="19dp"
- android:layout_height="19dp"
- android:src="@drawable/ic_pause_white_24dp" />
- </LinearLayout>
</RelativeLayout>
diff --git a/packages/SystemUI/res/layout/tv_pip_recents_overlay.xml b/packages/SystemUI/res/layout/tv_pip_recents_overlay.xml
new file mode 100644
index 0000000..1e464d8
--- /dev/null
+++ b/packages/SystemUI/res/layout/tv_pip_recents_overlay.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical"
+ android:gravity="top|center_horizontal">
+
+ <com.android.systemui.tv.pip.PipRecentsControlsView
+ android:id="@+id/pip_controls"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent" />
+
+ <View
+ android:id="@+id/recents"
+ android:layout_width="1dp"
+ android:layout_height="1dp"
+ android:focusable="true" />
+</LinearLayout>
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index d897956..3fa6245 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -168,6 +168,8 @@
<string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Maak <xliff:g id="APP">%s</xliff:g> toe."</string>
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> verwerp."</string>
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Alle onlangse programme is toegemaak."</string>
+ <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+ <skip />
<string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Begin tans <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
<string name="accessibility_notification_dismissed" msgid="854211387186306927">"Kennisgewing is toegemaak."</string>
@@ -236,8 +238,7 @@
<string name="gps_notification_found_text" msgid="4619274244146446464">"Ligging deur GPS gestel"</string>
<string name="accessibility_location_active" msgid="2427290146138169014">"Liggingversoeke aktief"</string>
<string name="accessibility_clear_all" msgid="5235938559247164925">"Verwyder alle kennisgewings."</string>
- <!-- no translation found for notification_group_overflow_indicator (1863231301642314183) -->
- <skip />
+ <string name="notification_group_overflow_indicator" msgid="1863231301642314183">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string>
<string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"Kennisgewingsinstellings"</string>
<string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"<xliff:g id="APP_NAME">%s</xliff:g>-instellings"</string>
<string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Die skerm sal outomaties draai."</string>
@@ -310,8 +311,7 @@
<string name="recents_search_bar_label" msgid="8074997400187836677">"soek"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"Kon nie <xliff:g id="APP">%s</xliff:g> begin nie."</string>
<string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g> is in veiligmodus gedeaktiveer."</string>
- <string name="recents_history_button_label" msgid="5153358867807604821">"Geskiedenis"</string>
- <string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Vee uit"</string>
+ <string name="recents_stack_action_button_label" msgid="6593727103310426253">"Vee alles uit"</string>
<string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"Hierdie program steun nie veelvuldige vensters nie"</string>
<string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"Program steun nie veelvuldige vensters nie"</string>
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Verdeel horisontaal"</string>
@@ -480,8 +480,7 @@
<string name="notification_importance_max" msgid="5806278962376556491">"Wys boaan die kennisgewingslys, verskyn vlugtig op die skerm en laat klank toe"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Meer instellings"</string>
<string name="notification_done" msgid="5279426047273930175">"Klaar"</string>
- <!-- no translation found for notification_gear_accessibility (94429150213089611) -->
- <skip />
+ <string name="notification_gear_accessibility" msgid="94429150213089611">"<xliff:g id="APP_NAME">%1$s</xliff:g>-kennisgewingkontroles"</string>
<string name="color_and_appearance" msgid="1254323855964993144">"Kleur en voorkoms"</string>
<string name="night_mode" msgid="3540405868248625488">"Nagmodus"</string>
<string name="calibrate_display" msgid="5974642573432039217">"Kalibreer skerm"</string>
@@ -501,10 +500,48 @@
<string name="battery_detail_charging_summary" msgid="1279095653533044008">"Batterybespaarder is nie beskikbaar wanneer gelaai word nie"</string>
<string name="battery_detail_switch_title" msgid="6285872470260795421">"Batterybespaarder"</string>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"Verminder werkverrigting en agtergronddata"</string>
+ <string name="keyboard_key_button_template" msgid="6230056639734377300">"Knoppie <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="keyboard_key_home" msgid="2243500072071305073">"Home"</string>
+ <string name="keyboard_key_back" msgid="2337450286042721351">"Back"</string>
+ <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"Op"</string>
+ <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"Af"</string>
+ <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"Links"</string>
+ <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"Regs"</string>
+ <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"Middel"</string>
+ <string name="keyboard_key_tab" msgid="3871485650463164476">"Tab"</string>
+ <string name="keyboard_key_space" msgid="2499861316311153293">"Spasie"</string>
+ <string name="keyboard_key_enter" msgid="5739632123216118137">"Enter"</string>
+ <string name="keyboard_key_backspace" msgid="1559580097512385854">"Backspace"</string>
+ <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"Play/Pause"</string>
+ <string name="keyboard_key_media_stop" msgid="2859963958595908962">"Stop"</string>
+ <string name="keyboard_key_media_next" msgid="1894394911630345607">"Next"</string>
+ <string name="keyboard_key_media_previous" msgid="4256072387192967261">"Previous"</string>
+ <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"Rewind"</string>
+ <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"Fast Forward"</string>
+ <string name="keyboard_key_page_up" msgid="5654098530106845603">"Page Up"</string>
+ <string name="keyboard_key_page_down" msgid="8720502083731906136">"Page Down"</string>
+ <string name="keyboard_key_forward_del" msgid="1391451334716490176">"Delete"</string>
+ <string name="keyboard_key_move_home" msgid="2765693292069487486">"Home"</string>
+ <string name="keyboard_key_move_end" msgid="5901174332047975247">"End"</string>
+ <string name="keyboard_key_insert" msgid="8530501581636082614">"Insert"</string>
+ <string name="keyboard_key_num_lock" msgid="5052537581246772117">"Num Lock"</string>
+ <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"Syferpaneel <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"Stelsel"</string>
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Tuis"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Onlangs"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Terug"</string>
+ <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Kennisgewings"</string>
+ <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"Kortpadsleutels"</string>
+ <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"Wissel invoermetode"</string>
+ <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"Programme"</string>
+ <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"Bystand"</string>
+ <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"Blaaier"</string>
+ <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"Kontakte"</string>
+ <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"E-pos"</string>
+ <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"Kitsboodskappe"</string>
+ <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"Musiek"</string>
+ <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+ <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"Kalender"</string>
<string name="tuner_full_zen_title" msgid="4540823317772234308">"Wys saam met volumekontroles"</string>
<string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Moenie steur nie"</string>
<string name="volume_dnd_silent" msgid="4363882330723050727">"Volumeknoppieskortpad"</string>
@@ -540,8 +577,7 @@
<string name="select_keycode" msgid="7413765103381924584">"Kies Sleutelbordknoppie"</string>
<string name="preview" msgid="9077832302472282938">"Voorskou"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"Sleep om teëls by te voeg"</string>
- <!-- no translation found for drag_to_remove_tiles (3361212377437088062) -->
- <skip />
+ <string name="drag_to_remove_tiles" msgid="3361212377437088062">"Sleep hierheen om te verwyder"</string>
<string name="qs_edit" msgid="2232596095725105230">"Wysig"</string>
<string name="tuner_time" msgid="6572217313285536011">"Tyd"</string>
<string-array name="clock_options">
@@ -560,4 +596,14 @@
<string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Skuif op"</string>
<string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Skuif links"</string>
<string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Skuif regs"</string>
+ <string name="forced_resizable_info_text" msgid="7591061837558867999">"Program sal dalk nie met multivenster werk nie"</string>
+ <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"Posisie <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>. Dubbeltik om te wysig."</string>
+ <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. Dubbeltik om by te voeg."</string>
+ <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"Posisie <xliff:g id="POSITION">%1$d</xliff:g>. Dubbeltik om te kies."</string>
+ <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"Skuif <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"Verwyder <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="TILE_NAME">%1$s</xliff:g> is by posisie <xliff:g id="POSITION">%2$d</xliff:g> gevoeg"</string>
+ <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"<xliff:g id="TILE_NAME">%1$s</xliff:g> is verwyder"</string>
+ <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="TILE_NAME">%1$s</xliff:g> is na posisie <xliff:g id="POSITION">%2$d</xliff:g> geskuif"</string>
+ <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Kitsinstellingswysiger."</string>
</resources>
diff --git a/packages/SystemUI/res/values-af/strings_tv.xml b/packages/SystemUI/res/values-af/strings_tv.xml
index 391bf7d..0ed4860 100644
--- a/packages/SystemUI/res/values-af/strings_tv.xml
+++ b/packages/SystemUI/res/values-af/strings_tv.xml
@@ -26,6 +26,5 @@
<string name="pip_hold_home" msgid="340086535668778109">"Hou "<b>"TUIS"</b>" om PIP te beheer"</string>
<string name="pip_onboarding_description" msgid="2882896641362814195">"Druk en hou die TUIS-knoppie om PIP te beheer"</string>
<string name="pip_onboarding_button" msgid="3957426748484904611">"Het dit"</string>
- <!-- no translation found for recents_tv_dismiss (3555093879593377731) -->
- <skip />
+ <string name="recents_tv_dismiss" msgid="3555093879593377731">"Maak toe"</string>
</resources>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index 4286af0..eb5d256 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -168,6 +168,8 @@
<string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"<xliff:g id="APP">%s</xliff:g> አስወግድ።"</string>
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> ተሰናብቷል::"</string>
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"ሁሉም የቅርብ ጊዜ ማመልከቻዎች ተሰናብተዋል።"</string>
+ <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+ <skip />
<string name="accessibility_recents_item_launched" msgid="7616039892382525203">"<xliff:g id="APP">%s</xliff:g> በመጀመር ላይ።"</string>
<string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
<string name="accessibility_notification_dismissed" msgid="854211387186306927">"ማሳወቂያ ተወግዷል።"</string>
@@ -236,8 +238,7 @@
<string name="gps_notification_found_text" msgid="4619274244146446464">"በ GPS የተዘጋጀ ሥፍራ"</string>
<string name="accessibility_location_active" msgid="2427290146138169014">"የአካባቢ ጥያቄዎች ነቅተዋል"</string>
<string name="accessibility_clear_all" msgid="5235938559247164925">"ሁሉንም ማሳወቂያዎች አጽዳ"</string>
- <!-- no translation found for notification_group_overflow_indicator (1863231301642314183) -->
- <skip />
+ <string name="notification_group_overflow_indicator" msgid="1863231301642314183">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string>
<string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"የማሳወቂያ ቅንብሮች"</string>
<string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"የ<xliff:g id="APP_NAME">%s</xliff:g> ቅንብሮች"</string>
<string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"ማያ ገጽ በራስ ሰር ይዞራል።"</string>
@@ -310,8 +311,7 @@
<string name="recents_search_bar_label" msgid="8074997400187836677">"ፈልግ"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g>ን መጀመር አልተቻለም።"</string>
<string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g> በጥንቃቄ ሁነታ ውስጥ ታግዷል።"</string>
- <string name="recents_history_button_label" msgid="5153358867807604821">"ታሪክ"</string>
- <string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"ጥረግ"</string>
+ <string name="recents_stack_action_button_label" msgid="6593727103310426253">"ሁሉንም አጽዳ"</string>
<string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"ይህ መተግበሪያ ብዝሃ-መስኮትን አይደግፍም"</string>
<string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"መተግበሪያው ብዝሃ-መስኮትን አይደግፍም"</string>
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"አግድም ክፈል"</string>
@@ -480,8 +480,7 @@
<string name="notification_importance_max" msgid="5806278962376556491">"በማሳወቂያዎች ዝርዝር አናት ላይ አሳይ፣ ወደ ማያ ገጹ አሳይና ድምፅ ፍቀድ"</string>
<string name="notification_more_settings" msgid="816306283396553571">"ተጨማሪ ቅንብሮች"</string>
<string name="notification_done" msgid="5279426047273930175">"ተከናውኗል"</string>
- <!-- no translation found for notification_gear_accessibility (94429150213089611) -->
- <skip />
+ <string name="notification_gear_accessibility" msgid="94429150213089611">"<xliff:g id="APP_NAME">%1$s</xliff:g> ማሳወቂያ ቁጥጥሮች"</string>
<string name="color_and_appearance" msgid="1254323855964993144">"ቀለም እና መልክ"</string>
<string name="night_mode" msgid="3540405868248625488">"የሌሊት ሁነታ"</string>
<string name="calibrate_display" msgid="5974642573432039217">"ማሳያን ይለኩ"</string>
@@ -501,10 +500,48 @@
<string name="battery_detail_charging_summary" msgid="1279095653533044008">"ኃይል በሚሞላበት ጊዜ ባትሪ ቆጣቢ አይገኝም"</string>
<string name="battery_detail_switch_title" msgid="6285872470260795421">"ባትሪ ቆጣቢ"</string>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"አፈጻጸምን እና የጀርባ ውሂብን ይቀንሳል"</string>
+ <string name="keyboard_key_button_template" msgid="6230056639734377300">"አዝራር <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="keyboard_key_home" msgid="2243500072071305073">"መነሻ"</string>
+ <string name="keyboard_key_back" msgid="2337450286042721351">"ተመለስ"</string>
+ <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"ላይ"</string>
+ <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"ወደታች"</string>
+ <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"ግራ"</string>
+ <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"ቀኝ"</string>
+ <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"መሃል"</string>
+ <string name="keyboard_key_tab" msgid="3871485650463164476">"ትር"</string>
+ <string name="keyboard_key_space" msgid="2499861316311153293">"ክፍተት"</string>
+ <string name="keyboard_key_enter" msgid="5739632123216118137">"አስገባ"</string>
+ <string name="keyboard_key_backspace" msgid="1559580097512385854">"የኋሊት መደምሰሻ"</string>
+ <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"አጫውት/ለአፍታ አቁም"</string>
+ <string name="keyboard_key_media_stop" msgid="2859963958595908962">"አቁም"</string>
+ <string name="keyboard_key_media_next" msgid="1894394911630345607">"ቀጣይ"</string>
+ <string name="keyboard_key_media_previous" msgid="4256072387192967261">"ቀዳሚ"</string>
+ <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"ወደኋላ አጠንጥን"</string>
+ <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"በፍጥነት አሳልፍ"</string>
+ <string name="keyboard_key_page_up" msgid="5654098530106845603">"ገጽ ወደ ላይ"</string>
+ <string name="keyboard_key_page_down" msgid="8720502083731906136">"ገጽ ወደ ታች"</string>
+ <string name="keyboard_key_forward_del" msgid="1391451334716490176">"ሰርዝ"</string>
+ <string name="keyboard_key_move_home" msgid="2765693292069487486">"መነሻ"</string>
+ <string name="keyboard_key_move_end" msgid="5901174332047975247">"መጨረሻ"</string>
+ <string name="keyboard_key_insert" msgid="8530501581636082614">"አስገባ"</string>
+ <string name="keyboard_key_num_lock" msgid="5052537581246772117">"Num Lock"</string>
+ <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"የቁጥር ሰሌዳ <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"ሥርዓት"</string>
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"መነሻ"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"የቅርብ ጊዜዎቹ"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"ተመለስ"</string>
+ <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"ማሳወቂያዎች"</string>
+ <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"የቁልፍ ሰሌዳ አቋራጮች"</string>
+ <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"የግቤት ስልት ቀይር"</string>
+ <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"መተግበሪያዎች"</string>
+ <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"ረዳት"</string>
+ <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"አሳሽ"</string>
+ <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"እውቂያዎች"</string>
+ <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"ኢሜይል"</string>
+ <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"ፈጣን መልዕክት"</string>
+ <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"ሙዚቃ"</string>
+ <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+ <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"የቀን መቁጠሪያ"</string>
<string name="tuner_full_zen_title" msgid="4540823317772234308">"ከድምፅ መቆጣጠሪያዎች ጋር አሳይ"</string>
<string name="volume_and_do_not_disturb" msgid="3373784330208603030">"አትረብሽ"</string>
<string name="volume_dnd_silent" msgid="4363882330723050727">"የድምፅ አዝራሮች አቋራጭ"</string>
@@ -540,8 +577,7 @@
<string name="select_keycode" msgid="7413765103381924584">"የቁልፍ ሰሌዳ አዝራር ይምረጡ"</string>
<string name="preview" msgid="9077832302472282938">"ቅድመ-እይታ"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"ሰቆችን ለማከል ይጎትቱ"</string>
- <!-- no translation found for drag_to_remove_tiles (3361212377437088062) -->
- <skip />
+ <string name="drag_to_remove_tiles" msgid="3361212377437088062">"ለማስወገድ ወደዚህ ይጎትቱ"</string>
<string name="qs_edit" msgid="2232596095725105230">"አርትዕ"</string>
<string name="tuner_time" msgid="6572217313285536011">"ሰዓት"</string>
<string-array name="clock_options">
@@ -560,4 +596,14 @@
<string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"ወደ ላይ ሂድ"</string>
<string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"ወደ ግራ ሂድ"</string>
<string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"ወደ ቀኝ ሂድ"</string>
+ <string name="forced_resizable_info_text" msgid="7591061837558867999">"መተግበሪያ ከብዝሃ-መስኮት ጋር ላይሠራ ይችላል"</string>
+ <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"ቦታ <xliff:g id="POSITION">%1$d</xliff:g>፣ <xliff:g id="TILE_NAME">%2$s</xliff:g>። ለማርትዕ ሁለቴ መታ ያድርጉ።"</string>
+ <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>። ለማከል ሁለቴ መታ ያድርጉ።"</string>
+ <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"ቦታ <xliff:g id="POSITION">%1$d</xliff:g>። ለመምረጥ ሁለቴ መታ ያድርጉ።"</string>
+ <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"<xliff:g id="TILE_NAME">%1$s</xliff:g>ን ይውሰዱ"</string>
+ <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"<xliff:g id="TILE_NAME">%1$s</xliff:g>ን ያስወግዱ"</string>
+ <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="TILE_NAME">%1$s</xliff:g> ወደ ቦታ <xliff:g id="POSITION">%2$d</xliff:g> ታክሏል"</string>
+ <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"<xliff:g id="TILE_NAME">%1$s</xliff:g> ተወግዷል"</string>
+ <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="TILE_NAME">%1$s</xliff:g> ወደ ቦታ <xliff:g id="POSITION">%2$d</xliff:g> ተወስዷል"</string>
+ <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"የፈጣን ቅንብሮች አርታዒ።"</string>
</resources>
diff --git a/packages/SystemUI/res/values-am/strings_tv.xml b/packages/SystemUI/res/values-am/strings_tv.xml
index 19e27ca..9df1916 100644
--- a/packages/SystemUI/res/values-am/strings_tv.xml
+++ b/packages/SystemUI/res/values-am/strings_tv.xml
@@ -26,6 +26,5 @@
<string name="pip_hold_home" msgid="340086535668778109">"PIPን ለመቆጣጠር "<b>"መነሻ"</b>"ን ይያዙ"</string>
<string name="pip_onboarding_description" msgid="2882896641362814195">"PIPን ለመቆጣጠር የመነሻ አዝራሩን ተጭነው ይያዙ"</string>
<string name="pip_onboarding_button" msgid="3957426748484904611">"ገባኝ"</string>
- <!-- no translation found for recents_tv_dismiss (3555093879593377731) -->
- <skip />
+ <string name="recents_tv_dismiss" msgid="3555093879593377731">"አሰናብት"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index 5d859ac..82a772c 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -172,6 +172,8 @@
<string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"إزالة <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"تمت إزالة <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"تم تجاهل كل التطبيقات المستخدمة مؤخرًا."</string>
+ <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+ <skip />
<string name="accessibility_recents_item_launched" msgid="7616039892382525203">"جارٍ بدء <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
<string name="accessibility_notification_dismissed" msgid="854211387186306927">"تم تجاهل الإشعار."</string>
@@ -240,8 +242,7 @@
<string name="gps_notification_found_text" msgid="4619274244146446464">"تم تعيين الموقع بواسطة GPS"</string>
<string name="accessibility_location_active" msgid="2427290146138169014">"طلبات الموقع نشطة"</string>
<string name="accessibility_clear_all" msgid="5235938559247164925">"محو جميع الإشعارات."</string>
- <!-- no translation found for notification_group_overflow_indicator (1863231301642314183) -->
- <skip />
+ <string name="notification_group_overflow_indicator" msgid="1863231301642314183">"و<xliff:g id="NUMBER">%s</xliff:g>"</string>
<string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"إعدادات الإشعارات"</string>
<string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"إعدادات <xliff:g id="APP_NAME">%s</xliff:g>"</string>
<string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"سيتم تدوير الشاشة تلقائيًا."</string>
@@ -314,8 +315,7 @@
<string name="recents_search_bar_label" msgid="8074997400187836677">"بحث"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"تعذر بدء <xliff:g id="APP">%s</xliff:g>."</string>
<string name="recents_launch_disabled_message" msgid="1624523193008871793">"تم تعطيل <xliff:g id="APP">%s</xliff:g> في الوضع الآمن."</string>
- <string name="recents_history_button_label" msgid="5153358867807604821">"السجلّ"</string>
- <string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"محو"</string>
+ <string name="recents_stack_action_button_label" msgid="6593727103310426253">"مسح الكل"</string>
<string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"لا يتيح هذا التطبيق النوافذ المتعددة."</string>
<string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"لا يتيح التطبيق النوافذ المتعددة."</string>
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"تقسيم أفقي"</string>
@@ -484,8 +484,7 @@
<string name="notification_importance_max" msgid="5806278962376556491">"عرض هذا الإشعار بأعلى قائمة الإشعارات وعرضه بسرعة على الشاشة مع السماح بإصدار تنبيه صوتي"</string>
<string name="notification_more_settings" msgid="816306283396553571">"المزيد من الإعدادات"</string>
<string name="notification_done" msgid="5279426047273930175">"تم"</string>
- <!-- no translation found for notification_gear_accessibility (94429150213089611) -->
- <skip />
+ <string name="notification_gear_accessibility" msgid="94429150213089611">"عناصر التحكم في إشعارات <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="color_and_appearance" msgid="1254323855964993144">"اللون والمظهر"</string>
<string name="night_mode" msgid="3540405868248625488">"الوضع الليلي"</string>
<string name="calibrate_display" msgid="5974642573432039217">"معايرة الشاشة"</string>
@@ -505,10 +504,48 @@
<string name="battery_detail_charging_summary" msgid="1279095653533044008">"وضع توفير شحن البطارية غير متاح أثناء الشحن."</string>
<string name="battery_detail_switch_title" msgid="6285872470260795421">"توفير شحن البطارية"</string>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"لخفض مستوى الأداء وبيانات الخلفية"</string>
+ <string name="keyboard_key_button_template" msgid="6230056639734377300">"الزر <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="keyboard_key_home" msgid="2243500072071305073">"Home"</string>
+ <string name="keyboard_key_back" msgid="2337450286042721351">"Back"</string>
+ <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"أعلى"</string>
+ <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"أسفل"</string>
+ <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"يسار"</string>
+ <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"يمين"</string>
+ <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"وسط"</string>
+ <string name="keyboard_key_tab" msgid="3871485650463164476">"Tab"</string>
+ <string name="keyboard_key_space" msgid="2499861316311153293">"مسافة"</string>
+ <string name="keyboard_key_enter" msgid="5739632123216118137">"Enter"</string>
+ <string name="keyboard_key_backspace" msgid="1559580097512385854">"Backspace"</string>
+ <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"تشغيل / إيقاف مؤقت"</string>
+ <string name="keyboard_key_media_stop" msgid="2859963958595908962">"إيقاف"</string>
+ <string name="keyboard_key_media_next" msgid="1894394911630345607">"التالي"</string>
+ <string name="keyboard_key_media_previous" msgid="4256072387192967261">"السابق"</string>
+ <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"إرجاع"</string>
+ <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"تقديم سريع"</string>
+ <string name="keyboard_key_page_up" msgid="5654098530106845603">"Page Up"</string>
+ <string name="keyboard_key_page_down" msgid="8720502083731906136">"Page Down"</string>
+ <string name="keyboard_key_forward_del" msgid="1391451334716490176">"Delete"</string>
+ <string name="keyboard_key_move_home" msgid="2765693292069487486">"الرئيسية"</string>
+ <string name="keyboard_key_move_end" msgid="5901174332047975247">"End"</string>
+ <string name="keyboard_key_insert" msgid="8530501581636082614">"Insert"</string>
+ <string name="keyboard_key_num_lock" msgid="5052537581246772117">"Num Lock"</string>
+ <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"لوحة الأرقام <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"النظام"</string>
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"الشاشة الرئيسية"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"الأحدث"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"رجوع"</string>
+ <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"الإشعارات"</string>
+ <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"اختصارات لوحة المفاتيح"</string>
+ <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"تبديل أسلوب الإدخال"</string>
+ <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"التطبيقات"</string>
+ <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"التطبيق المساعد"</string>
+ <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"المتصفح"</string>
+ <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"جهات الاتصال"</string>
+ <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"البريد الإلكتروني"</string>
+ <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"الرسائل الفورية"</string>
+ <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"الموسيقى"</string>
+ <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+ <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"التقويم"</string>
<string name="tuner_full_zen_title" msgid="4540823317772234308">"عرض مع عناصر التحكم في مستوى الصوت"</string>
<string name="volume_and_do_not_disturb" msgid="3373784330208603030">"الرجاء عدم الإزعاج"</string>
<string name="volume_dnd_silent" msgid="4363882330723050727">"اختصار أزرار مستوى الصوت"</string>
@@ -563,4 +600,14 @@
<string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"نقل لأعلى"</string>
<string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"نقل لليسار"</string>
<string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"نقل لليمين"</string>
+ <string name="forced_resizable_info_text" msgid="7591061837558867999">"يمكن ألا يعمل التطبيق مع وضع النوافذ المتعددة."</string>
+ <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"الموضع <xliff:g id="POSITION">%1$d</xliff:g>، <xliff:g id="TILE_NAME">%2$s</xliff:g>. انقر نقرًا مزدوجًا للتعديل."</string>
+ <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. انقر نقرًا مزدوجًا للإضافة."</string>
+ <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"الموضع <xliff:g id="POSITION">%1$d</xliff:g>. انقر نقرًا مزدوجًا للتحديد."</string>
+ <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"نقل <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"إزالة <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"تمت إضافة <xliff:g id="TILE_NAME">%1$s</xliff:g> إلى الموضع <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+ <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"تمت إزالة <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"تم نقل <xliff:g id="TILE_NAME">%1$s</xliff:g> إلى الموضع <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+ <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"برنامج تعديل الإعدادات السريعة."</string>
</resources>
diff --git a/packages/SystemUI/res/values-ar/strings_tv.xml b/packages/SystemUI/res/values-ar/strings_tv.xml
index db91b69..e6fbffc 100644
--- a/packages/SystemUI/res/values-ar/strings_tv.xml
+++ b/packages/SystemUI/res/values-ar/strings_tv.xml
@@ -26,6 +26,5 @@
<string name="pip_hold_home" msgid="340086535668778109">"اضغط "<b>"الرئيسية"</b>" للتحكم في PIP"</string>
<string name="pip_onboarding_description" msgid="2882896641362814195">"اضغط مع الاستمرار على زر الشاشة الرئيسية للتحكم في PIP"</string>
<string name="pip_onboarding_button" msgid="3957426748484904611">"حسنًا"</string>
- <!-- no translation found for recents_tv_dismiss (3555093879593377731) -->
- <skip />
+ <string name="recents_tv_dismiss" msgid="3555093879593377731">"رفض"</string>
</resources>
diff --git a/packages/SystemUI/res/values-az-rAZ/strings.xml b/packages/SystemUI/res/values-az-rAZ/strings.xml
index ad106f4..59b3141 100644
--- a/packages/SystemUI/res/values-az-rAZ/strings.xml
+++ b/packages/SystemUI/res/values-az-rAZ/strings.xml
@@ -168,6 +168,8 @@
<string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"<xliff:g id="APP">%s</xliff:g> kənarlaşdırın."</string>
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> çıxarıldı."</string>
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Bütün son tətbiqlər kənarlaşdırıldı."</string>
+ <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+ <skip />
<string name="accessibility_recents_item_launched" msgid="7616039892382525203">"<xliff:g id="APP">%s</xliff:g> başlanır."</string>
<string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
<string name="accessibility_notification_dismissed" msgid="854211387186306927">"Bildiriş uzaqlaşdırıldı."</string>
@@ -236,8 +238,7 @@
<string name="gps_notification_found_text" msgid="4619274244146446464">"Yer GPS tərəfindən müəyyən edildi"</string>
<string name="accessibility_location_active" msgid="2427290146138169014">"Məkan sorğuları arxivi"</string>
<string name="accessibility_clear_all" msgid="5235938559247164925">"Bütün bildirişləri sil."</string>
- <!-- no translation found for notification_group_overflow_indicator (1863231301642314183) -->
- <skip />
+ <string name="notification_group_overflow_indicator" msgid="1863231301642314183">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string>
<string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"Bildiriş ayarları"</string>
<string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"<xliff:g id="APP_NAME">%s</xliff:g> ayarları"</string>
<string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Ekran avtomatik döndəriləcək."</string>
@@ -310,8 +311,7 @@
<string name="recents_search_bar_label" msgid="8074997400187836677">"axtarış"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g> başlana bilmir."</string>
<string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g> güvənli rejimdə deaktiv edildi."</string>
- <string name="recents_history_button_label" msgid="5153358867807604821">"Tarixçə"</string>
- <string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Təmizləyin"</string>
+ <string name="recents_stack_action_button_label" msgid="6593727103310426253">"Hamısını silin"</string>
<string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"Bu tətbiq çoxsaylı pəncərəni dəstəkləmir"</string>
<string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"Bu tətbiq çoxsaylı pəncərəni dəstəkləyir"</string>
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Üfüqi Böl"</string>
@@ -480,8 +480,7 @@
<string name="notification_importance_max" msgid="5806278962376556491">"Bildirişlər siyahısında yuxarıda göstərin, ekrana nəzər salın və səsə icazə verin"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Daha çox ayar"</string>
<string name="notification_done" msgid="5279426047273930175">"Hazırdır"</string>
- <!-- no translation found for notification_gear_accessibility (94429150213089611) -->
- <skip />
+ <string name="notification_gear_accessibility" msgid="94429150213089611">"<xliff:g id="APP_NAME">%1$s</xliff:g> bildiriş nəzarəti"</string>
<string name="color_and_appearance" msgid="1254323855964993144">"Rəng və görünüş"</string>
<string name="night_mode" msgid="3540405868248625488">"Gecə rejimi"</string>
<string name="calibrate_display" msgid="5974642573432039217">"Ekranı kalibrləyin"</string>
@@ -501,10 +500,48 @@
<string name="battery_detail_charging_summary" msgid="1279095653533044008">"Enerji Qənaəti doldurulma zamanı əlçatan deyil"</string>
<string name="battery_detail_switch_title" msgid="6285872470260795421">"Enerji Qənaəti"</string>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"Performansı azaldır və arxa fon datasını məhdudlaşdırır"</string>
+ <string name="keyboard_key_button_template" msgid="6230056639734377300">"Düymə <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="keyboard_key_home" msgid="2243500072071305073">"Əsas səhifə"</string>
+ <string name="keyboard_key_back" msgid="2337450286042721351">"Geri"</string>
+ <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"Yuxarı"</string>
+ <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"Aşağı"</string>
+ <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"Sol"</string>
+ <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"Sağ"</string>
+ <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"Mərkəz"</string>
+ <string name="keyboard_key_tab" msgid="3871485650463164476">"Tab"</string>
+ <string name="keyboard_key_space" msgid="2499861316311153293">"Boşluq"</string>
+ <string name="keyboard_key_enter" msgid="5739632123216118137">"Daxil olun"</string>
+ <string name="keyboard_key_backspace" msgid="1559580097512385854">"Gerisil"</string>
+ <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"Oxut/Durdur"</string>
+ <string name="keyboard_key_media_stop" msgid="2859963958595908962">"Dayandırın"</string>
+ <string name="keyboard_key_media_next" msgid="1894394911630345607">"Növbəti"</string>
+ <string name="keyboard_key_media_previous" msgid="4256072387192967261">"Öncəki"</string>
+ <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"Geri ötürmə"</string>
+ <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"İrəli Ötürmə"</string>
+ <string name="keyboard_key_page_up" msgid="5654098530106845603">"Yuxarı Səhifə"</string>
+ <string name="keyboard_key_page_down" msgid="8720502083731906136">"Aşağı Səhifə"</string>
+ <string name="keyboard_key_forward_del" msgid="1391451334716490176">"Silin"</string>
+ <string name="keyboard_key_move_home" msgid="2765693292069487486">"Əsas səhifə"</string>
+ <string name="keyboard_key_move_end" msgid="5901174332047975247">"Son"</string>
+ <string name="keyboard_key_insert" msgid="8530501581636082614">"Daxil edin"</string>
+ <string name="keyboard_key_num_lock" msgid="5052537581246772117">"Nömrələr"</string>
+ <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"Rəqəmli düymələr <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"Sistem"</string>
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Əsas səhifə"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Sonuncular"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Geri"</string>
+ <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Bildirişlər"</string>
+ <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"Klaviatura qısa yolları"</string>
+ <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"Daxiletmə metoduna keçin"</string>
+ <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"Tətbiqlər"</string>
+ <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"Yardım"</string>
+ <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"Brauzer"</string>
+ <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"Kontaktlar"</string>
+ <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"E-poçt"</string>
+ <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"IM"</string>
+ <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"Musiqi"</string>
+ <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+ <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"Təqvim"</string>
<string name="tuner_full_zen_title" msgid="4540823317772234308">"Həcm nəzarəti ilə göstərin"</string>
<string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Narahat etməyin"</string>
<string name="volume_dnd_silent" msgid="4363882330723050727">"Səs düymələri qısayolu"</string>
@@ -540,8 +577,7 @@
<string name="select_keycode" msgid="7413765103381924584">"Klaviatura Düyməsi Seçin"</string>
<string name="preview" msgid="9077832302472282938">"Önizləmə"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"Xanalar əlavə etmək üçün sürüşdürün"</string>
- <!-- no translation found for drag_to_remove_tiles (3361212377437088062) -->
- <skip />
+ <string name="drag_to_remove_tiles" msgid="3361212377437088062">"Silmək üçün bura sürüşdürün"</string>
<string name="qs_edit" msgid="2232596095725105230">"Redaktə edin"</string>
<string name="tuner_time" msgid="6572217313285536011">"Vaxt"</string>
<string-array name="clock_options">
@@ -560,4 +596,14 @@
<string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Yuxarıya keçin"</string>
<string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Sola köçürün"</string>
<string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Sağa köçürün"</string>
+ <string name="forced_resizable_info_text" msgid="7591061837558867999">"Tətbiq çoxsaylı pəncərə ilə işləməyə bilər."</string>
+ <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"<xliff:g id="POSITION">%1$d</xliff:g> mövqeyi, <xliff:g id="TILE_NAME">%2$s</xliff:g>. Redaktə etmək üçün iki dəfə tıklayın."</string>
+ <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. Əlavə etmək üçün iki dəfə tıklayın."</string>
+ <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"<xliff:g id="POSITION">%1$d</xliff:g> mövqeyi. Seçmək üçün iki dəfə tıklayın."</string>
+ <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"<xliff:g id="TILE_NAME">%1$s</xliff:g> köçürün"</string>
+ <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"<xliff:g id="TILE_NAME">%1$s</xliff:g> silin"</string>
+ <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="TILE_NAME">%1$s</xliff:g> <xliff:g id="POSITION">%2$d</xliff:g> mövqeyinə əlavə edildi"</string>
+ <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"<xliff:g id="TILE_NAME">%1$s</xliff:g> silindi"</string>
+ <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="TILE_NAME">%1$s</xliff:g> <xliff:g id="POSITION">%2$d</xliff:g> mövqeyinə köçürüldü"</string>
+ <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Sürətli ayarlar redaktoru."</string>
</resources>
diff --git a/packages/SystemUI/res/values-az-rAZ/strings_tv.xml b/packages/SystemUI/res/values-az-rAZ/strings_tv.xml
index a7a6c5d..63fc9fd 100644
--- a/packages/SystemUI/res/values-az-rAZ/strings_tv.xml
+++ b/packages/SystemUI/res/values-az-rAZ/strings_tv.xml
@@ -26,6 +26,5 @@
<string name="pip_hold_home" msgid="340086535668778109">"PIP idarı etmək üçün "<b>"Əsas səhifəni"</b>" tutub saxlayın"</string>
<string name="pip_onboarding_description" msgid="2882896641362814195">"PİP nəzarət etmək üçün ƏSAS EKRAN düyməni basıb saxlayın"</string>
<string name="pip_onboarding_button" msgid="3957426748484904611">"Anladım"</string>
- <!-- no translation found for recents_tv_dismiss (3555093879593377731) -->
- <skip />
+ <string name="recents_tv_dismiss" msgid="3555093879593377731">"Rədd edin"</string>
</resources>
diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
index edec332..0945885 100644
--- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml
+++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
@@ -169,6 +169,8 @@
<string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Odbacite <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"Aplikacija <xliff:g id="APP">%s</xliff:g> je odbačena."</string>
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Sve nedavno korišćene aplikacije su odbačene."</string>
+ <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+ <skip />
<string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Pokrećemo <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
<string name="accessibility_notification_dismissed" msgid="854211387186306927">"Obaveštenje je odbačeno."</string>
@@ -237,8 +239,7 @@
<string name="gps_notification_found_text" msgid="4619274244146446464">"Lokaciju je podesio GPS"</string>
<string name="accessibility_location_active" msgid="2427290146138169014">"Ima aktivnih zahteva za lokaciju"</string>
<string name="accessibility_clear_all" msgid="5235938559247164925">"Obriši sva obaveštenja."</string>
- <!-- no translation found for notification_group_overflow_indicator (1863231301642314183) -->
- <skip />
+ <string name="notification_group_overflow_indicator" msgid="1863231301642314183">"i još <xliff:g id="NUMBER">%s</xliff:g>"</string>
<string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"Podešavanja obaveštenja"</string>
<string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"Podešavanja za <xliff:g id="APP_NAME">%s</xliff:g>"</string>
<string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Ekran će se automatski rotirati."</string>
@@ -311,8 +312,7 @@
<string name="recents_search_bar_label" msgid="8074997400187836677">"pretraži"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"Pokretanje aplikacije <xliff:g id="APP">%s</xliff:g> nije uspelo."</string>
<string name="recents_launch_disabled_message" msgid="1624523193008871793">"Aplikacija <xliff:g id="APP">%s</xliff:g> je onemogućena u bezbednom režimu."</string>
- <string name="recents_history_button_label" msgid="5153358867807604821">"Istorija"</string>
- <string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Obriši"</string>
+ <string name="recents_stack_action_button_label" msgid="6593727103310426253">"Obriši sve"</string>
<string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"Ova aplikacija ne podržava režim sa više prozora"</string>
<string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"Aplikacija ne podržava režim sa više prozora"</string>
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Podeli horizontalno"</string>
@@ -481,8 +481,7 @@
<string name="notification_importance_max" msgid="5806278962376556491">"Prikazuju se u vrhu liste obaveštenja, nakratko se prikazuju na ekranu i emituju zvuk"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Još podešavanja"</string>
<string name="notification_done" msgid="5279426047273930175">"Gotovo"</string>
- <!-- no translation found for notification_gear_accessibility (94429150213089611) -->
- <skip />
+ <string name="notification_gear_accessibility" msgid="94429150213089611">"Kontrole obaveštenja za aplikaciju <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="color_and_appearance" msgid="1254323855964993144">"Boja i izgled"</string>
<string name="night_mode" msgid="3540405868248625488">"Noćni režim"</string>
<string name="calibrate_display" msgid="5974642573432039217">"Kalibrišite ekran"</string>
@@ -502,10 +501,48 @@
<string name="battery_detail_charging_summary" msgid="1279095653533044008">"Ušteda baterije nije dostupna tokom punjenja"</string>
<string name="battery_detail_switch_title" msgid="6285872470260795421">"Ušteda baterije"</string>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"Smanjuje performanse i pozadinske podatke"</string>
+ <string name="keyboard_key_button_template" msgid="6230056639734377300">"Dugme <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="keyboard_key_home" msgid="2243500072071305073">"Taster Početna"</string>
+ <string name="keyboard_key_back" msgid="2337450286042721351">"Taster Nazad"</string>
+ <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"Taster sa strelicom nagore"</string>
+ <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"Taster sa strelicom nadole"</string>
+ <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"Taster sa strelicom nalevo"</string>
+ <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"Taster sa strelicom nadesno"</string>
+ <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"Taster sa centralnom strelicom"</string>
+ <string name="keyboard_key_tab" msgid="3871485650463164476">"Tabulator"</string>
+ <string name="keyboard_key_space" msgid="2499861316311153293">"Taster za razmak"</string>
+ <string name="keyboard_key_enter" msgid="5739632123216118137">"Enter"</string>
+ <string name="keyboard_key_backspace" msgid="1559580097512385854">"Taster za brisanje unazad"</string>
+ <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"Taster za reprodukciju/pauziranje"</string>
+ <string name="keyboard_key_media_stop" msgid="2859963958595908962">"Taster za zaustavljanje"</string>
+ <string name="keyboard_key_media_next" msgid="1894394911630345607">"Taster Sledeća"</string>
+ <string name="keyboard_key_media_previous" msgid="4256072387192967261">"Taster Prethodna"</string>
+ <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"Taster za premotavanje unazad"</string>
+ <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"Taster za premotavanje unapred"</string>
+ <string name="keyboard_key_page_up" msgid="5654098530106845603">"Taster za stranicu nagore"</string>
+ <string name="keyboard_key_page_down" msgid="8720502083731906136">"Taster za stranicu nadole"</string>
+ <string name="keyboard_key_forward_del" msgid="1391451334716490176">"Taster za brisanje"</string>
+ <string name="keyboard_key_move_home" msgid="2765693292069487486">"Taster Početna"</string>
+ <string name="keyboard_key_move_end" msgid="5901174332047975247">"Taster za kraj"</string>
+ <string name="keyboard_key_insert" msgid="8530501581636082614">"Taster za umetanje"</string>
+ <string name="keyboard_key_num_lock" msgid="5052537581246772117">"Num Lock"</string>
+ <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"Taster <xliff:g id="NAME">%1$s</xliff:g> na numeričkoj tastaturi"</string>
<string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"Sistem"</string>
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Početni"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Nedavni sadržaj"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Nazad"</string>
+ <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Obaveštenja"</string>
+ <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"Tasterske prečice"</string>
+ <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"Promeni metod unosa"</string>
+ <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"Aplikacije"</string>
+ <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"Aplikacija za pomoć"</string>
+ <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"Pregledač"</string>
+ <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"Kontakti"</string>
+ <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"Imejl"</string>
+ <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"Razmena trenutnih poruka"</string>
+ <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"Muzika"</string>
+ <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+ <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"Kalendar"</string>
<string name="tuner_full_zen_title" msgid="4540823317772234308">"Prikaži sa kontrolama jačine zvuka"</string>
<string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Ne uznemiravaj"</string>
<string name="volume_dnd_silent" msgid="4363882330723050727">"Prečica za dugmad za jačinu zvuka"</string>
@@ -560,4 +597,14 @@
<string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Pomeri nagore"</string>
<string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Pomeri ulevo"</string>
<string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Pomeri udesno"</string>
+ <string name="forced_resizable_info_text" msgid="7591061837558867999">"Aplikacija možda neće funkcionisati sa više prozora"</string>
+ <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"<xliff:g id="POSITION">%1$d</xliff:g>. pozicija, <xliff:g id="TILE_NAME">%2$s</xliff:g>. Dvaput dodirnite da biste izmenili."</string>
+ <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. Dvaput dodirnite da biste dodali."</string>
+ <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"<xliff:g id="POSITION">%1$d</xliff:g>. pozicija. Dvaput dodirnite da biste izabrali."</string>
+ <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"Premesti pločicu <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"Ukloni pločicu <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"Pločica <xliff:g id="TILE_NAME">%1$s</xliff:g> je dodata na <xliff:g id="POSITION">%2$d</xliff:g>. poziciju"</string>
+ <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"Pločica <xliff:g id="TILE_NAME">%1$s</xliff:g> je uklonjena"</string>
+ <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"Pločica <xliff:g id="TILE_NAME">%1$s</xliff:g> je premeštena na <xliff:g id="POSITION">%2$d</xliff:g>. poziciju"</string>
+ <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Uređivač za Brza podešavanja."</string>
</resources>
diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings_tv.xml b/packages/SystemUI/res/values-b+sr+Latn/strings_tv.xml
index a285627..d026d2c 100644
--- a/packages/SystemUI/res/values-b+sr+Latn/strings_tv.xml
+++ b/packages/SystemUI/res/values-b+sr+Latn/strings_tv.xml
@@ -26,6 +26,5 @@
<string name="pip_hold_home" msgid="340086535668778109"><b>"POČETNI EKRAN"</b>" kont. PIP"</string>
<string name="pip_onboarding_description" msgid="2882896641362814195">"Pritisnite i zadržite dugme POČETNI EKRAN da biste kontrolisali PIP"</string>
<string name="pip_onboarding_button" msgid="3957426748484904611">"Važi"</string>
- <!-- no translation found for recents_tv_dismiss (3555093879593377731) -->
- <skip />
+ <string name="recents_tv_dismiss" msgid="3555093879593377731">"Odbaci"</string>
</resources>
diff --git a/packages/SystemUI/res/values-be-rBY/strings.xml b/packages/SystemUI/res/values-be-rBY/strings.xml
index e5771d7..726a0e7 100644
--- a/packages/SystemUI/res/values-be-rBY/strings.xml
+++ b/packages/SystemUI/res/values-be-rBY/strings.xml
@@ -172,6 +172,8 @@
<string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Выдаліць <xliff:g id="APP">%s</xliff:g> са спіса апошніх."</string>
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> выдалены."</string>
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Усе апошнія праграмы адхілены."</string>
+ <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+ <skip />
<string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Запускаецца <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
<string name="accessibility_notification_dismissed" msgid="854211387186306927">"Апавяшчэнне прапушчана."</string>
@@ -240,8 +242,7 @@
<string name="gps_notification_found_text" msgid="4619274244146446464">"Месца задана праз GPS"</string>
<string name="accessibility_location_active" msgid="2427290146138169014">"Ёсць актыўныя запыты пра месцазнаходжанне"</string>
<string name="accessibility_clear_all" msgid="5235938559247164925">"Выдалiць усе апавяшчэннi."</string>
- <!-- no translation found for notification_group_overflow_indicator (1863231301642314183) -->
- <skip />
+ <string name="notification_group_overflow_indicator" msgid="1863231301642314183">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string>
<string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"Налады апавяшчэнняў"</string>
<string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"Налады <xliff:g id="APP_NAME">%s</xliff:g>"</string>
<string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Экран паварочваецца аўтаматычна."</string>
@@ -314,8 +315,7 @@
<string name="recents_search_bar_label" msgid="8074997400187836677">"пошук"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"Не атрымалася запусціць <xliff:g id="APP">%s</xliff:g>."</string>
<string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g> адключана ў бяспечным рэжыме."</string>
- <string name="recents_history_button_label" msgid="5153358867807604821">"Гісторыя"</string>
- <string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Ачысціць"</string>
+ <string name="recents_stack_action_button_label" msgid="6593727103310426253">"Ачысціць усё"</string>
<string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"Гэта праграма не падтрымлівае функцыю некалькіх вокнаў"</string>
<string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"Праграма не падтрымлівае функцыю некалькіх вокнаў"</string>
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Падзяліць гарызантальна"</string>
@@ -484,8 +484,7 @@
<string name="notification_importance_max" msgid="5806278962376556491">"Паказваць уверсе спіса апавяшчэнняў, хутка паказаць на экране і дазволіць прайграванне гуку"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Дадатковыя налады"</string>
<string name="notification_done" msgid="5279426047273930175">"Гатова"</string>
- <!-- no translation found for notification_gear_accessibility (94429150213089611) -->
- <skip />
+ <string name="notification_gear_accessibility" msgid="94429150213089611">"Элементы кантролю апавяшчэнняў <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="color_and_appearance" msgid="1254323855964993144">"Колер і выгляд"</string>
<string name="night_mode" msgid="3540405868248625488">"Начны рэжым"</string>
<string name="calibrate_display" msgid="5974642573432039217">"Каліброўка дысплэя"</string>
@@ -505,10 +504,48 @@
<string name="battery_detail_charging_summary" msgid="1279095653533044008">"Эканомія зараду акумулятара недаступная падчас зарадкі"</string>
<string name="battery_detail_switch_title" msgid="6285872470260795421">"Эканомія зараду"</string>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"Памяншае прадукцыйнасць і фонавую перадачу даных"</string>
+ <string name="keyboard_key_button_template" msgid="6230056639734377300">"Кнопка <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="keyboard_key_home" msgid="2243500072071305073">"Home"</string>
+ <string name="keyboard_key_back" msgid="2337450286042721351">"Назад"</string>
+ <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"Уверх"</string>
+ <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"Уніз"</string>
+ <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"Улева"</string>
+ <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"Управа"</string>
+ <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"Цэнтр"</string>
+ <string name="keyboard_key_tab" msgid="3871485650463164476">"Tab"</string>
+ <string name="keyboard_key_space" msgid="2499861316311153293">"Прабел"</string>
+ <string name="keyboard_key_enter" msgid="5739632123216118137">"Enter"</string>
+ <string name="keyboard_key_backspace" msgid="1559580097512385854">"Backspace"</string>
+ <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"Прайграванне/Паўза"</string>
+ <string name="keyboard_key_media_stop" msgid="2859963958595908962">"Спыніць"</string>
+ <string name="keyboard_key_media_next" msgid="1894394911630345607">"Наступны"</string>
+ <string name="keyboard_key_media_previous" msgid="4256072387192967261">"Папярэдні"</string>
+ <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"Перамотка назад"</string>
+ <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"Перамотка ўперад"</string>
+ <string name="keyboard_key_page_up" msgid="5654098530106845603">"Page Up"</string>
+ <string name="keyboard_key_page_down" msgid="8720502083731906136">"Page Down"</string>
+ <string name="keyboard_key_forward_del" msgid="1391451334716490176">"Delete"</string>
+ <string name="keyboard_key_move_home" msgid="2765693292069487486">"Home"</string>
+ <string name="keyboard_key_move_end" msgid="5901174332047975247">"End"</string>
+ <string name="keyboard_key_insert" msgid="8530501581636082614">"Insert"</string>
+ <string name="keyboard_key_num_lock" msgid="5052537581246772117">"Num Lock"</string>
+ <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"Лічбавая клавіятура: <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"Сістэмныя"</string>
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Галоўная"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Апошнія"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Назад"</string>
+ <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Апавяшчэнні"</string>
+ <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"Спалучэнні клавіш для хуткага доступу"</string>
+ <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"Пераключэнне рэжыму ўводу"</string>
+ <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"Праграмы"</string>
+ <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"Памочнік"</string>
+ <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"Браўзер"</string>
+ <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"Кантакты"</string>
+ <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"Электронная пошта"</string>
+ <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"Iмгненныя паведамленнi"</string>
+ <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"Музыка"</string>
+ <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+ <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"Каляндар"</string>
<string name="tuner_full_zen_title" msgid="4540823317772234308">"Паказаць з рэгулятарамі гучнасці"</string>
<string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Не турбаваць"</string>
<string name="volume_dnd_silent" msgid="4363882330723050727">"Доступ праз кнопкі рэгулявання гучнасці"</string>
@@ -544,8 +581,7 @@
<string name="select_keycode" msgid="7413765103381924584">"Выберыце клавішу клавіятуры"</string>
<string name="preview" msgid="9077832302472282938">"Папярэдні прагляд"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"Перацягніце, каб дадаць пліткі"</string>
- <!-- no translation found for drag_to_remove_tiles (3361212377437088062) -->
- <skip />
+ <string name="drag_to_remove_tiles" msgid="3361212377437088062">"Перацягніце сюды, каб выдаліць"</string>
<string name="qs_edit" msgid="2232596095725105230">"Рэдагаваць"</string>
<string name="tuner_time" msgid="6572217313285536011">"Час"</string>
<string-array name="clock_options">
@@ -564,4 +600,14 @@
<string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Перамясціць уверх"</string>
<string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Перамясціць улева"</string>
<string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Перамясціць управа"</string>
+ <string name="forced_resizable_info_text" msgid="7591061837558867999">"Праграма можа не працаваць у рэжыме некалькіх вокнаў"</string>
+ <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"Месца: <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>. Краніце двойчы, каб рэдагаваць."</string>
+ <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. Краніце двойчы, каб дадаць."</string>
+ <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"Месца: <xliff:g id="POSITION">%1$d</xliff:g>. Краніце двойчы, каб выбраць."</string>
+ <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"Перамясціць <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"Выдаліць <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"Плітка <xliff:g id="TILE_NAME">%1$s</xliff:g> дададзена ў наступнае месца: <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+ <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"Плітка <xliff:g id="TILE_NAME">%1$s</xliff:g> выдалена"</string>
+ <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="TILE_NAME">%1$s</xliff:g> перамешчана ў наступнае месца: <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+ <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Рэдактар хуткіх налад."</string>
</resources>
diff --git a/packages/SystemUI/res/values-be-rBY/strings_tv.xml b/packages/SystemUI/res/values-be-rBY/strings_tv.xml
index 1c93d24..6138155 100644
--- a/packages/SystemUI/res/values-be-rBY/strings_tv.xml
+++ b/packages/SystemUI/res/values-be-rBY/strings_tv.xml
@@ -29,6 +29,5 @@
<string name="pip_hold_home" msgid="340086535668778109">"Утрым. "<b>"HOME"</b>" для кір. PIP"</string>
<string name="pip_onboarding_description" msgid="2882896641362814195">"Націсніце і ўтрымлівайце кнопку HOME для кіравання PIP"</string>
<string name="pip_onboarding_button" msgid="3957426748484904611">"Зразумела"</string>
- <!-- no translation found for recents_tv_dismiss (3555093879593377731) -->
- <skip />
+ <string name="recents_tv_dismiss" msgid="3555093879593377731">"Адхіліць"</string>
</resources>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index 6c65f9f..479087a 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -168,6 +168,8 @@
<string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Отхвърляне на <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"Приложението <xliff:g id="APP">%s</xliff:g> е отхвърлено."</string>
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Всички скорошни приложения са отхвърлени."</string>
+ <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+ <skip />
<string name="accessibility_recents_item_launched" msgid="7616039892382525203">"<xliff:g id="APP">%s</xliff:g> се стартира."</string>
<string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
<string name="accessibility_notification_dismissed" msgid="854211387186306927">"Известието е отхвърлено."</string>
@@ -236,8 +238,7 @@
<string name="gps_notification_found_text" msgid="4619274244146446464">"Местоположението е зададено от GPS"</string>
<string name="accessibility_location_active" msgid="2427290146138169014">"Активни заявки за местоположение"</string>
<string name="accessibility_clear_all" msgid="5235938559247164925">"Изчистване на всички известия."</string>
- <!-- no translation found for notification_group_overflow_indicator (1863231301642314183) -->
- <skip />
+ <string name="notification_group_overflow_indicator" msgid="1863231301642314183">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string>
<string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"Настройки за известия"</string>
<string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"Настройки за <xliff:g id="APP_NAME">%s</xliff:g>"</string>
<string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Екранът ще се завърта автоматично."</string>
@@ -310,8 +311,7 @@
<string name="recents_search_bar_label" msgid="8074997400187836677">"търсене"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g> не можа да стартира."</string>
<string name="recents_launch_disabled_message" msgid="1624523193008871793">"Приложението <xliff:g id="APP">%s</xliff:g> е деактивирано в безопасния режим."</string>
- <string name="recents_history_button_label" msgid="5153358867807604821">"История"</string>
- <string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Изчистване"</string>
+ <string name="recents_stack_action_button_label" msgid="6593727103310426253">"Изчистване на всичко"</string>
<string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"Това приложение не поддържа няколко прозореца"</string>
<string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"Приложението не поддържа няколко прозореца"</string>
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Хоризонтално разделяне"</string>
@@ -480,8 +480,7 @@
<string name="notification_importance_max" msgid="5806278962376556491">"Показване най-горе в списъка с известия, както и на екрана и разрешаване на звуков сигнал"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Още настройки"</string>
<string name="notification_done" msgid="5279426047273930175">"Готово"</string>
- <!-- no translation found for notification_gear_accessibility (94429150213089611) -->
- <skip />
+ <string name="notification_gear_accessibility" msgid="94429150213089611">"Контроли за известията от <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="color_and_appearance" msgid="1254323855964993144">"Цвят и облик"</string>
<string name="night_mode" msgid="3540405868248625488">"Нощен режим"</string>
<string name="calibrate_display" msgid="5974642573432039217">"Калибриране на дисплея"</string>
@@ -501,10 +500,48 @@
<string name="battery_detail_charging_summary" msgid="1279095653533044008">"Режимът за запазване на батерията не е налице при зареждане"</string>
<string name="battery_detail_switch_title" msgid="6285872470260795421">"Режим за запазване на батерията"</string>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"Намалява ефективността и данните на заден план"</string>
+ <string name="keyboard_key_button_template" msgid="6230056639734377300">"Бутон „<xliff:g id="NAME">%1$s</xliff:g>“"</string>
+ <string name="keyboard_key_home" msgid="2243500072071305073">"Начало"</string>
+ <string name="keyboard_key_back" msgid="2337450286042721351">"Назад"</string>
+ <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"Нагоре"</string>
+ <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"Надолу"</string>
+ <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"Наляво"</string>
+ <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"Надясно"</string>
+ <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"Център"</string>
+ <string name="keyboard_key_tab" msgid="3871485650463164476">"Tab"</string>
+ <string name="keyboard_key_space" msgid="2499861316311153293">"Интервал"</string>
+ <string name="keyboard_key_enter" msgid="5739632123216118137">"Enter"</string>
+ <string name="keyboard_key_backspace" msgid="1559580097512385854">"Backspace"</string>
+ <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"Пускане/пауза"</string>
+ <string name="keyboard_key_media_stop" msgid="2859963958595908962">"Спиране"</string>
+ <string name="keyboard_key_media_next" msgid="1894394911630345607">"Напред"</string>
+ <string name="keyboard_key_media_previous" msgid="4256072387192967261">"Назад"</string>
+ <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"Превъртане назад"</string>
+ <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"Превъртане напред"</string>
+ <string name="keyboard_key_page_up" msgid="5654098530106845603">"Страница нагоре"</string>
+ <string name="keyboard_key_page_down" msgid="8720502083731906136">"Страница надолу"</string>
+ <string name="keyboard_key_forward_del" msgid="1391451334716490176">"Изтриване"</string>
+ <string name="keyboard_key_move_home" msgid="2765693292069487486">"Home"</string>
+ <string name="keyboard_key_move_end" msgid="5901174332047975247">"End"</string>
+ <string name="keyboard_key_insert" msgid="8530501581636082614">"Insert"</string>
+ <string name="keyboard_key_num_lock" msgid="5052537581246772117">"Num Lock"</string>
+ <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"Цифрова клавиатура – <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"Системни"</string>
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Начало"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Скорошни"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Назад"</string>
+ <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Известия"</string>
+ <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"Клавишни комбинации"</string>
+ <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"Превключване на метода на въвеждане"</string>
+ <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"Приложения"</string>
+ <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"Помощно приложение"</string>
+ <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"Браузър"</string>
+ <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"Контакти"</string>
+ <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"Електронна поща"</string>
+ <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"Незабавни съобщения"</string>
+ <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"Музика"</string>
+ <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+ <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"Календар"</string>
<string name="tuner_full_zen_title" msgid="4540823317772234308">"Показване с контролите за силата на звука"</string>
<string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Не безпокойте"</string>
<string name="volume_dnd_silent" msgid="4363882330723050727">"Пряк път към бутоните за силата на звука"</string>
@@ -559,4 +596,14 @@
<string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Преместване нагоре"</string>
<string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Преместване наляво"</string>
<string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Преместване надясно"</string>
+ <string name="forced_resizable_info_text" msgid="7591061837558867999">"Приложението може да не работи в режим за няколко прозореца"</string>
+ <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"Позиция <xliff:g id="POSITION">%1$d</xliff:g>, „<xliff:g id="TILE_NAME">%2$s</xliff:g>“. Докоснете двукратно, за да редактирате."</string>
+ <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"„<xliff:g id="TILE_NAME">%1$s</xliff:g>“. Докоснете двукратно, за да добавите."</string>
+ <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"Позиция <xliff:g id="POSITION">%1$d</xliff:g>. Докоснете двукратно, за да изберете."</string>
+ <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"Преместване на „<xliff:g id="TILE_NAME">%1$s</xliff:g>“"</string>
+ <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"Премахване на „<xliff:g id="TILE_NAME">%1$s</xliff:g>“"</string>
+ <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"Добавихте „<xliff:g id="TILE_NAME">%1$s</xliff:g>“ към позиция <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+ <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"Премахнахте „<xliff:g id="TILE_NAME">%1$s</xliff:g>“"</string>
+ <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"Преместихте „<xliff:g id="TILE_NAME">%1$s</xliff:g>“ на позиция <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+ <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Редактор за бързи настройки."</string>
</resources>
diff --git a/packages/SystemUI/res/values-bg/strings_tv.xml b/packages/SystemUI/res/values-bg/strings_tv.xml
index 9926ef8..38e251b 100644
--- a/packages/SystemUI/res/values-bg/strings_tv.xml
+++ b/packages/SystemUI/res/values-bg/strings_tv.xml
@@ -26,6 +26,5 @@
<string name="pip_hold_home" msgid="340086535668778109">"Контр. на PIP: Задр. "<b>"HOME"</b></string>
<string name="pip_onboarding_description" msgid="2882896641362814195">"За контролиране на PIP натиснете и задръжте бутона „HOME“"</string>
<string name="pip_onboarding_button" msgid="3957426748484904611">"Разбрах"</string>
- <!-- no translation found for recents_tv_dismiss (3555093879593377731) -->
- <skip />
+ <string name="recents_tv_dismiss" msgid="3555093879593377731">"Отхвърляне"</string>
</resources>
diff --git a/packages/SystemUI/res/values-bn-rBD/strings.xml b/packages/SystemUI/res/values-bn-rBD/strings.xml
index 446d4af..ccbcb6e 100644
--- a/packages/SystemUI/res/values-bn-rBD/strings.xml
+++ b/packages/SystemUI/res/values-bn-rBD/strings.xml
@@ -168,6 +168,8 @@
<string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"<xliff:g id="APP">%s</xliff:g> খারিজ করুন।"</string>
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> খারিজ করা হয়েছে৷"</string>
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"সমস্ত সাম্প্রতিক অ্যাপ্লিকেশন খারিজ করা হয়েছে।"</string>
+ <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+ <skip />
<string name="accessibility_recents_item_launched" msgid="7616039892382525203">"<xliff:g id="APP">%s</xliff:g> তারাঙ্কিত করা হচ্ছে।"</string>
<string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
<string name="accessibility_notification_dismissed" msgid="854211387186306927">"বিজ্ঞপ্তি খারিজ করা হয়েছে৷"</string>
@@ -236,8 +238,7 @@
<string name="gps_notification_found_text" msgid="4619274244146446464">"GPS এর দ্বারা সেট করা অবস্থান"</string>
<string name="accessibility_location_active" msgid="2427290146138169014">"অবস্থান অনুরোধ সক্রিয় রয়েছে"</string>
<string name="accessibility_clear_all" msgid="5235938559247164925">"সমস্ত বিজ্ঞপ্তি সাফ করুন৷"</string>
- <!-- no translation found for notification_group_overflow_indicator (1863231301642314183) -->
- <skip />
+ <string name="notification_group_overflow_indicator" msgid="1863231301642314183">"+ <xliff:g id="NUMBER">%s</xliff:g>টি"</string>
<string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"বিজ্ঞপ্তির সেটিংস"</string>
<string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"<xliff:g id="APP_NAME">%s</xliff:g> সেটিংস"</string>
<string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"স্ক্রীন স্বয়ংক্রিয়ভাবে ঘুরে যাবে৷"</string>
@@ -310,8 +311,7 @@
<string name="recents_search_bar_label" msgid="8074997400187836677">"অনুসন্ধান"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g> শুরু করা যায়নি৷"</string>
<string name="recents_launch_disabled_message" msgid="1624523193008871793">"নিরাপদ মোডে <xliff:g id="APP">%s</xliff:g> অক্ষম করা হয়েছে৷"</string>
- <string name="recents_history_button_label" msgid="5153358867807604821">"ইতিহাস"</string>
- <string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"সাফ করুন"</string>
+ <string name="recents_stack_action_button_label" msgid="6593727103310426253">"সবকিছু সাফ করুন"</string>
<string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"এই অ্যাপ্লিকেশানটি মাল্টি-উইন্ডো সমর্থন করে না"</string>
<string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"অ্যাপ্লিকেশানগুলি মাল্টি-উইন্ডো সমর্থন করে না"</string>
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"অনুভূমিক স্প্লিট"</string>
@@ -480,8 +480,7 @@
<string name="notification_importance_max" msgid="5806278962376556491">"বিজ্ঞপ্তি তালিকার শীর্ষে দেখানো হয় এবং স্ক্রীনের উপরে প্রদর্শিত এবং শব্দ করার মঞ্জুরি দেয়"</string>
<string name="notification_more_settings" msgid="816306283396553571">"আরো সেটিংস"</string>
<string name="notification_done" msgid="5279426047273930175">"সম্পন্ন"</string>
- <!-- no translation found for notification_gear_accessibility (94429150213089611) -->
- <skip />
+ <string name="notification_gear_accessibility" msgid="94429150213089611">"<xliff:g id="APP_NAME">%1$s</xliff:g> বিজ্ঞপ্তির নিয়ন্ত্রণগুলি"</string>
<string name="color_and_appearance" msgid="1254323855964993144">"রঙ এবং চেহারা"</string>
<string name="night_mode" msgid="3540405868248625488">"রাতের মোড"</string>
<string name="calibrate_display" msgid="5974642573432039217">"প্রদর্শন ক্যালিব্রেট করুন"</string>
@@ -501,10 +500,48 @@
<string name="battery_detail_charging_summary" msgid="1279095653533044008">"চার্জ করার সময় ব্যাটারি সেভার উপলব্ধ নয়"</string>
<string name="battery_detail_switch_title" msgid="6285872470260795421">"ব্যাটারি সেভার"</string>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"কার্য-সম্পাদনা ও পশ্চাদপট ডেটাকে কমিয়ে দেয়"</string>
+ <string name="keyboard_key_button_template" msgid="6230056639734377300">"<xliff:g id="NAME">%1$s</xliff:g> বোতাম"</string>
+ <string name="keyboard_key_home" msgid="2243500072071305073">"হোম"</string>
+ <string name="keyboard_key_back" msgid="2337450286042721351">"ফিরুন"</string>
+ <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"উপরে"</string>
+ <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"নীচে"</string>
+ <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"বাম"</string>
+ <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"ডান"</string>
+ <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"কেন্দ্র"</string>
+ <string name="keyboard_key_tab" msgid="3871485650463164476">"ট্যাব"</string>
+ <string name="keyboard_key_space" msgid="2499861316311153293">"স্পেস"</string>
+ <string name="keyboard_key_enter" msgid="5739632123216118137">"এন্টার"</string>
+ <string name="keyboard_key_backspace" msgid="1559580097512385854">"ব্যাকস্পেস"</string>
+ <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"প্লে/বিরতি"</string>
+ <string name="keyboard_key_media_stop" msgid="2859963958595908962">"থামান"</string>
+ <string name="keyboard_key_media_next" msgid="1894394911630345607">"পরবর্তী"</string>
+ <string name="keyboard_key_media_previous" msgid="4256072387192967261">"পূর্ববর্তী"</string>
+ <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"পেছনের দিকে যান"</string>
+ <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"দ্রুত ফরওয়ার্ড"</string>
+ <string name="keyboard_key_page_up" msgid="5654098530106845603">"পেজ আপ"</string>
+ <string name="keyboard_key_page_down" msgid="8720502083731906136">"পেজ ডাউন"</string>
+ <string name="keyboard_key_forward_del" msgid="1391451334716490176">"মুছুন"</string>
+ <string name="keyboard_key_move_home" msgid="2765693292069487486">"হোম"</string>
+ <string name="keyboard_key_move_end" msgid="5901174332047975247">"শেষ"</string>
+ <string name="keyboard_key_insert" msgid="8530501581636082614">"ঢোকান"</string>
+ <string name="keyboard_key_num_lock" msgid="5052537581246772117">"সংখ্যা লক"</string>
+ <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"সংখ্যাপ্যাড <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"সিস্টেম"</string>
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"হোম"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"সাম্প্রতিকগুলি"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"পিছনে"</string>
+ <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"বিজ্ঞপ্তিগুলি"</string>
+ <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"কীবোর্ড শর্টকাট"</string>
+ <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"ইনপুট পদ্ধতি পাল্টান"</string>
+ <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"অ্যাপ্লিকেশানগুলি"</string>
+ <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"সহযোগিতা"</string>
+ <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"ব্রাউজার"</string>
+ <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"পরিচিতি"</string>
+ <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"ইমেল"</string>
+ <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"IM"</string>
+ <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"সংগীত"</string>
+ <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+ <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"ক্যালেন্ডার"</string>
<string name="tuner_full_zen_title" msgid="4540823317772234308">"ভলিউম নিয়ন্ত্রণ সহ দেখান"</string>
<string name="volume_and_do_not_disturb" msgid="3373784330208603030">"বিরক্ত করবেন না"</string>
<string name="volume_dnd_silent" msgid="4363882330723050727">"ভলিউম বোতামের শর্টকাট"</string>
@@ -544,8 +581,8 @@
<string name="qs_edit" msgid="2232596095725105230">"সম্পাদনা করুন"</string>
<string name="tuner_time" msgid="6572217313285536011">"সময়"</string>
<string-array name="clock_options">
- <item msgid="5965318737560463480">"ঘন্টা, মিনিট, এবং সেকেন্ড দেখান"</item>
- <item msgid="1427801730816895300">"ঘন্টা এবং মিনিট দেখান (ডিফল্ট)"</item>
+ <item msgid="5965318737560463480">"ঘণ্টা, মিনিট, এবং সেকেন্ড দেখান"</item>
+ <item msgid="1427801730816895300">"ঘণ্টা এবং মিনিট দেখান (ডিফল্ট)"</item>
<item msgid="3830170141562534721">"এই আইকনটি দেখাবেন না"</item>
</string-array>
<string-array name="battery_options">
@@ -559,4 +596,14 @@
<string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"উপরে সরান"</string>
<string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"বাঁয়ে সরান"</string>
<string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"ডানে সরান"</string>
+ <string name="forced_resizable_info_text" msgid="7591061837558867999">"একাধিক-উইন্ডো দিয়ে অ্যাপ কাজ নাও করতে পারে"</string>
+ <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"<xliff:g id="POSITION">%1$d</xliff:g> অবস্থান, <xliff:g id="TILE_NAME">%2$s</xliff:g>৷ সম্পাদনা করতে দুবার আলতো চাপুন৷"</string>
+ <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>৷ যোগ করতে দুবার আলতো চাপুন৷"</string>
+ <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"<xliff:g id="POSITION">%1$d</xliff:g> অবস্থান৷ নির্বাচন করতে দুবার আলতো চাপুন৷"</string>
+ <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"<xliff:g id="TILE_NAME">%1$s</xliff:g> সরান"</string>
+ <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"<xliff:g id="TILE_NAME">%1$s</xliff:g> সরান"</string>
+ <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="POSITION">%2$d</xliff:g> অবস্থানে <xliff:g id="TILE_NAME">%1$s</xliff:g> যোগ করা হয়েছে"</string>
+ <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"<xliff:g id="TILE_NAME">%1$s</xliff:g> মোছা হয়েছে"</string>
+ <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="TILE_NAME">%1$s</xliff:g> <xliff:g id="POSITION">%2$d</xliff:g> এ সরানো হয়েছে"</string>
+ <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"দ্রুত সেটিংস সম্পাদক৷"</string>
</resources>
diff --git a/packages/SystemUI/res/values-bn-rBD/strings_tv.xml b/packages/SystemUI/res/values-bn-rBD/strings_tv.xml
index cbed4a1..6fa2d5b 100644
--- a/packages/SystemUI/res/values-bn-rBD/strings_tv.xml
+++ b/packages/SystemUI/res/values-bn-rBD/strings_tv.xml
@@ -26,6 +26,5 @@
<string name="pip_hold_home" msgid="340086535668778109">"PIP নিয়ন্ত্রণ করতে "<b>"হোম"</b>" কী ধরে রাখুন"</string>
<string name="pip_onboarding_description" msgid="2882896641362814195">"PIP নিয়ন্ত্রণ করতে HOME বোতামটিকে টিপুন ও ধরে থাকুন"</string>
<string name="pip_onboarding_button" msgid="3957426748484904611">"বুঝেছি"</string>
- <!-- no translation found for recents_tv_dismiss (3555093879593377731) -->
- <skip />
+ <string name="recents_tv_dismiss" msgid="3555093879593377731">"খারিজ করুন"</string>
</resources>
diff --git a/packages/SystemUI/res/values-bs-rBA/strings.xml b/packages/SystemUI/res/values-bs-rBA/strings.xml
index 024bf70..f1be672 100644
--- a/packages/SystemUI/res/values-bs-rBA/strings.xml
+++ b/packages/SystemUI/res/values-bs-rBA/strings.xml
@@ -169,6 +169,8 @@
<string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Odbaci aplikaciju <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"Aplikacija <xliff:g id="APP">%s</xliff:g> uklonjena."</string>
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Sve nedavno korištene aplikacije su odbačene."</string>
+ <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+ <skip />
<string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Pokrećem aplikaciju <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
<string name="accessibility_notification_dismissed" msgid="854211387186306927">"Obavještenje je uklonjeno."</string>
@@ -237,8 +239,7 @@
<string name="gps_notification_found_text" msgid="4619274244146446464">"Lokacija utvrđena GPS signalom"</string>
<string name="accessibility_location_active" msgid="2427290146138169014">"Aktiviran je zahtjev za lokaciju"</string>
<string name="accessibility_clear_all" msgid="5235938559247164925">"Uklanjanje svih obavještenja."</string>
- <!-- no translation found for notification_group_overflow_indicator (1863231301642314183) -->
- <skip />
+ <string name="notification_group_overflow_indicator" msgid="1863231301642314183">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string>
<string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"Postavke obavještenja"</string>
<string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"Postavke aplikacije <xliff:g id="APP_NAME">%s</xliff:g>"</string>
<string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Ekran će se automatski rotirati."</string>
@@ -311,8 +312,7 @@
<string name="recents_search_bar_label" msgid="8074997400187836677">"pretraga"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"Aplikacija <xliff:g id="APP">%s</xliff:g> nije pokrenuta."</string>
<string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g> je onemogućena u sigurnom načinu rada."</string>
- <string name="recents_history_button_label" msgid="5153358867807604821">"Historija"</string>
- <string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Obriši"</string>
+ <string name="recents_stack_action_button_label" msgid="6593727103310426253">"Obriši sve"</string>
<string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"Ova aplikacija ne podržava rad sa više prozora"</string>
<string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"Aplikacija ne podržava rad sa više prozora"</string>
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Podjela po horizontali"</string>
@@ -481,8 +481,7 @@
<string name="notification_importance_max" msgid="5806278962376556491">"Prikaži na vrhu liste obavještenja, kratko prikaži na ekranu i dozvoli zvuk"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Više postavki"</string>
<string name="notification_done" msgid="5279426047273930175">"Gotovo"</string>
- <!-- no translation found for notification_gear_accessibility (94429150213089611) -->
- <skip />
+ <string name="notification_gear_accessibility" msgid="94429150213089611">"Kontrole <xliff:g id="APP_NAME">%1$s</xliff:g> obavještenja"</string>
<string name="color_and_appearance" msgid="1254323855964993144">"Boja i izgled"</string>
<string name="night_mode" msgid="3540405868248625488">"Noćni način rada"</string>
<string name="calibrate_display" msgid="5974642573432039217">"Kalibracija zaslona"</string>
@@ -502,10 +501,60 @@
<string name="battery_detail_charging_summary" msgid="1279095653533044008">"Ušteda baterije je isključena prilikom punjenja"</string>
<string name="battery_detail_switch_title" msgid="6285872470260795421">"Ušteda baterije"</string>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"Ograničava rad i prijenos podataka u pozadini"</string>
+ <string name="keyboard_key_button_template" msgid="6230056639734377300">"Dugme <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="keyboard_key_home" msgid="2243500072071305073">"Tipka za početak"</string>
+ <string name="keyboard_key_back" msgid="2337450286042721351">"Nazad"</string>
+ <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"Gore"</string>
+ <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"Dolje"</string>
+ <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"Lijevo"</string>
+ <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"Desno"</string>
+ <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"Sredina"</string>
+ <string name="keyboard_key_tab" msgid="3871485650463164476">"Tabulator"</string>
+ <string name="keyboard_key_space" msgid="2499861316311153293">"Razmaknica"</string>
+ <string name="keyboard_key_enter" msgid="5739632123216118137">"Tipka za novi red"</string>
+ <string name="keyboard_key_backspace" msgid="1559580097512385854">"Tipka za brisanje"</string>
+ <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"Pokreni/pauziraj"</string>
+ <string name="keyboard_key_media_stop" msgid="2859963958595908962">"Zaustavi"</string>
+ <string name="keyboard_key_media_next" msgid="1894394911630345607">"Sljedeće"</string>
+ <string name="keyboard_key_media_previous" msgid="4256072387192967261">"Prethodno"</string>
+ <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"Premotaj"</string>
+ <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"Ubrzaj"</string>
+ <string name="keyboard_key_page_up" msgid="5654098530106845603">"Tipka Page Up"</string>
+ <string name="keyboard_key_page_down" msgid="8720502083731906136">"Tipka Page Down"</string>
+ <string name="keyboard_key_forward_del" msgid="1391451334716490176">"Tipka za brisanje"</string>
+ <string name="keyboard_key_move_home" msgid="2765693292069487486">"Tipka za početak"</string>
+ <string name="keyboard_key_move_end" msgid="5901174332047975247">"Kraj"</string>
+ <string name="keyboard_key_insert" msgid="8530501581636082614">"Tipka za umetanje"</string>
+ <string name="keyboard_key_num_lock" msgid="5052537581246772117">"Tipka Num Lock"</string>
+ <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"Numerička tastatura <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"Sistem"</string>
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Početak"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Nedavni ekrani"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Nazad"</string>
+ <!-- no translation found for keyboard_shortcut_group_system_notifications (8366964080041773224) -->
+ <skip />
+ <!-- no translation found for keyboard_shortcut_group_system_shortcuts_helper (4892255911160332762) -->
+ <skip />
+ <!-- no translation found for keyboard_shortcut_group_system_switch_input (2334164096341310324) -->
+ <skip />
+ <!-- no translation found for keyboard_shortcut_group_applications (9129465955073449206) -->
+ <skip />
+ <!-- no translation found for keyboard_shortcut_group_applications_assist (9095441910537146013) -->
+ <skip />
+ <!-- no translation found for keyboard_shortcut_group_applications_browser (6465985474000766533) -->
+ <skip />
+ <!-- no translation found for keyboard_shortcut_group_applications_contacts (2064197111278436375) -->
+ <skip />
+ <!-- no translation found for keyboard_shortcut_group_applications_email (6257036897441939004) -->
+ <skip />
+ <!-- no translation found for keyboard_shortcut_group_applications_im (1892749399083161405) -->
+ <skip />
+ <!-- no translation found for keyboard_shortcut_group_applications_music (4775559515850922780) -->
+ <skip />
+ <!-- no translation found for keyboard_shortcut_group_applications_youtube (6555453761294723317) -->
+ <skip />
+ <!-- no translation found for keyboard_shortcut_group_applications_calendar (9043614299194991263) -->
+ <skip />
<string name="tuner_full_zen_title" msgid="4540823317772234308">"Prikazati sa kontrolama jačine zvuka"</string>
<string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Ne ometaj"</string>
<string name="volume_dnd_silent" msgid="4363882330723050727">"Prečica za dugmad za Jačinu zvuka"</string>
@@ -541,8 +590,7 @@
<string name="select_keycode" msgid="7413765103381924584">"Odaberite dugme na tastaturi"</string>
<string name="preview" msgid="9077832302472282938">"Pregledaj"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"Povucite da biste dodali polja"</string>
- <!-- no translation found for drag_to_remove_tiles (3361212377437088062) -->
- <skip />
+ <string name="drag_to_remove_tiles" msgid="3361212377437088062">"Prevucite ovdje za uklanjanje"</string>
<string name="qs_edit" msgid="2232596095725105230">"Uredi"</string>
<string name="tuner_time" msgid="6572217313285536011">"Vrijeme"</string>
<string-array name="clock_options">
@@ -561,4 +609,14 @@
<string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Pomjeri gore"</string>
<string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Pomjeri lijevo"</string>
<string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Pomjeri desno"</string>
+ <string name="forced_resizable_info_text" msgid="7591061837558867999">"Aplikacija možda neće raditi s višestrukim prozorom"</string>
+ <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"Pozicija <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>. Dvaput dodirnite za uređivanje."</string>
+ <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g> Dvaput dodirnite za dodavanje."</string>
+ <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"Pozicija <xliff:g id="POSITION">%1$d</xliff:g>. Dvaput dodirnite za odabir."</string>
+ <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"Pomjeri <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"Ukloni <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="TILE_NAME">%1$s</xliff:g> je dodan na poziciju <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+ <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"<xliff:g id="TILE_NAME">%1$s</xliff:g> je uklonjen"</string>
+ <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="TILE_NAME">%1$s</xliff:g> je premješten na poziciju <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+ <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Uređivanje brzih postavki"</string>
</resources>
diff --git a/packages/SystemUI/res/values-bs-rBA/strings_tv.xml b/packages/SystemUI/res/values-bs-rBA/strings_tv.xml
index 5d20c8c..65c0982 100644
--- a/packages/SystemUI/res/values-bs-rBA/strings_tv.xml
+++ b/packages/SystemUI/res/values-bs-rBA/strings_tv.xml
@@ -29,6 +29,5 @@
<string name="pip_hold_home" msgid="340086535668778109">"Za kontr. PIP držite "<b>"HOME"</b></string>
<string name="pip_onboarding_description" msgid="2882896641362814195">"Za kontrolu PIP, pritisnite i držite dugme POČETAK"</string>
<string name="pip_onboarding_button" msgid="3957426748484904611">"Jasno mi je"</string>
- <!-- no translation found for recents_tv_dismiss (3555093879593377731) -->
- <skip />
+ <string name="recents_tv_dismiss" msgid="3555093879593377731">"Odbaci"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index 645c84f..b7fffb7 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -168,6 +168,8 @@
<string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Ignora <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"S\'ha omès <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"S\'han descartat totes les aplicacions recents."</string>
+ <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+ <skip />
<string name="accessibility_recents_item_launched" msgid="7616039892382525203">"S\'està iniciant <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
<string name="accessibility_notification_dismissed" msgid="854211387186306927">"Notificació omesa."</string>
@@ -236,8 +238,7 @@
<string name="gps_notification_found_text" msgid="4619274244146446464">"S\'ha establert la ubicació per GPS"</string>
<string name="accessibility_location_active" msgid="2427290146138169014">"Sol·licituds d\'ubicació actives"</string>
<string name="accessibility_clear_all" msgid="5235938559247164925">"Esborra totes les notificacions."</string>
- <!-- no translation found for notification_group_overflow_indicator (1863231301642314183) -->
- <skip />
+ <string name="notification_group_overflow_indicator" msgid="1863231301642314183">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string>
<string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"Configuració de les notificacions"</string>
<string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"Configuració de l\'aplicació <xliff:g id="APP_NAME">%s</xliff:g>"</string>
<string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"La pantalla girarà automàticament."</string>
@@ -310,8 +311,7 @@
<string name="recents_search_bar_label" msgid="8074997400187836677">"cerca"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"No s\'ha pogut iniciar <xliff:g id="APP">%s</xliff:g>."</string>
<string name="recents_launch_disabled_message" msgid="1624523193008871793">"En mode segur, l\'aplicació <xliff:g id="APP">%s</xliff:g> està desactivada."</string>
- <string name="recents_history_button_label" msgid="5153358867807604821">"Historial"</string>
- <string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Esborra"</string>
+ <string name="recents_stack_action_button_label" msgid="6593727103310426253">"Esborra-ho tot"</string>
<string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"Aquesta aplicació no admet el mode multifinestra"</string>
<string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"L\'aplicació no admet el mode multifinestra"</string>
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Divisió horitzontal"</string>
@@ -480,8 +480,7 @@
<string name="notification_importance_max" msgid="5806278962376556491">"Les notificacions es mostren al capdamunt de la llista, apareixen a la pantalla i poden emetre sons"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Més opcions"</string>
<string name="notification_done" msgid="5279426047273930175">"Fet"</string>
- <!-- no translation found for notification_gear_accessibility (94429150213089611) -->
- <skip />
+ <string name="notification_gear_accessibility" msgid="94429150213089611">"Controls de notificació de l\'aplicació <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="color_and_appearance" msgid="1254323855964993144">"Color i aparença"</string>
<string name="night_mode" msgid="3540405868248625488">"Mode nocturn"</string>
<string name="calibrate_display" msgid="5974642573432039217">"Calibra la pantalla"</string>
@@ -501,10 +500,48 @@
<string name="battery_detail_charging_summary" msgid="1279095653533044008">"La funció Estalvi de bateria no està disponible durant la càrrega"</string>
<string name="battery_detail_switch_title" msgid="6285872470260795421">"Estalvi de bateria"</string>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"Redueix el rendiment i les dades en segon pla"</string>
+ <string name="keyboard_key_button_template" msgid="6230056639734377300">"Botó <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="keyboard_key_home" msgid="2243500072071305073">"Inici"</string>
+ <string name="keyboard_key_back" msgid="2337450286042721351">"Enrere"</string>
+ <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"Amunt"</string>
+ <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"Avall"</string>
+ <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"Esquerra"</string>
+ <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"Dreta"</string>
+ <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"Centre"</string>
+ <string name="keyboard_key_tab" msgid="3871485650463164476">"Pestanya"</string>
+ <string name="keyboard_key_space" msgid="2499861316311153293">"Espai"</string>
+ <string name="keyboard_key_enter" msgid="5739632123216118137">"Retorn"</string>
+ <string name="keyboard_key_backspace" msgid="1559580097512385854">"Retrocés"</string>
+ <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"Reprodueix/Pausa"</string>
+ <string name="keyboard_key_media_stop" msgid="2859963958595908962">"Atura"</string>
+ <string name="keyboard_key_media_next" msgid="1894394911630345607">"Següent"</string>
+ <string name="keyboard_key_media_previous" msgid="4256072387192967261">"Anterior"</string>
+ <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"Rebobina"</string>
+ <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"Avança ràpidament"</string>
+ <string name="keyboard_key_page_up" msgid="5654098530106845603">"Re Pàg"</string>
+ <string name="keyboard_key_page_down" msgid="8720502083731906136">"Av Pàg"</string>
+ <string name="keyboard_key_forward_del" msgid="1391451334716490176">"Tecla de supressió"</string>
+ <string name="keyboard_key_move_home" msgid="2765693292069487486">"Inici"</string>
+ <string name="keyboard_key_move_end" msgid="5901174332047975247">"Final"</string>
+ <string name="keyboard_key_insert" msgid="8530501581636082614">"Tecla d\'inserció"</string>
+ <string name="keyboard_key_num_lock" msgid="5052537581246772117">"Bloqueig de teclat numèric"</string>
+ <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"Teclat numèric <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"Sistema"</string>
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Inici"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Recents"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Enrere"</string>
+ <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Notificacions"</string>
+ <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"Tecles de drecera"</string>
+ <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"Canvia el mètode d\'introducció"</string>
+ <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"Aplicacions"</string>
+ <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"Assistència"</string>
+ <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"Navegador"</string>
+ <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"Contactes"</string>
+ <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"Correu electrònic"</string>
+ <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"MI"</string>
+ <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"Music"</string>
+ <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+ <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"Calendari"</string>
<string name="tuner_full_zen_title" msgid="4540823317772234308">"Mostra amb els controls de volum"</string>
<string name="volume_and_do_not_disturb" msgid="3373784330208603030">"No molesteu"</string>
<string name="volume_dnd_silent" msgid="4363882330723050727">"Drecera per als botons de volum"</string>
@@ -559,4 +596,14 @@
<string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Mou amunt"</string>
<string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Mou a l\'esquerra"</string>
<string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Mou a la dreta"</string>
+ <string name="forced_resizable_info_text" msgid="7591061837558867999">"És possible que l\'aplicació no funcioni amb el Mode multifinestra"</string>
+ <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"Posició <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>. Fes doble toc per editar-la."</string>
+ <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. Fes doble toc per afegir-ho."</string>
+ <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"Posició <xliff:g id="POSITION">%1$d</xliff:g>. Fes doble toc per seleccionar-la."</string>
+ <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"Mou <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"Suprimeix <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="TILE_NAME">%1$s</xliff:g> s\'ha afegit a la posició <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+ <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"<xliff:g id="TILE_NAME">%1$s</xliff:g> s\'ha suprimit"</string>
+ <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="TILE_NAME">%1$s</xliff:g> s\'ha mogut a la posició <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+ <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Editor de la configuració ràpida."</string>
</resources>
diff --git a/packages/SystemUI/res/values-ca/strings_tv.xml b/packages/SystemUI/res/values-ca/strings_tv.xml
index 35482d4..8876664 100644
--- a/packages/SystemUI/res/values-ca/strings_tv.xml
+++ b/packages/SystemUI/res/values-ca/strings_tv.xml
@@ -26,6 +26,5 @@
<string name="pip_hold_home" msgid="340086535668778109">"Prem "<b>"INICI"</b>" per controlar PIP"</string>
<string name="pip_onboarding_description" msgid="2882896641362814195">"Mantén premut el botó INICI per controlar PIP"</string>
<string name="pip_onboarding_button" msgid="3957426748484904611">"D\'acord"</string>
- <!-- no translation found for recents_tv_dismiss (3555093879593377731) -->
- <skip />
+ <string name="recents_tv_dismiss" msgid="3555093879593377731">"Ignora"</string>
</resources>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index 5ce6bd9..b707ece 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -170,6 +170,8 @@
<string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Zavřít aplikaci <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"Aplikace <xliff:g id="APP">%s</xliff:g> byla odebrána."</string>
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Všechny naposledy použité aplikace byly odstraněny."</string>
+ <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+ <skip />
<string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Spouštění aplikace <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
<string name="accessibility_notification_dismissed" msgid="854211387186306927">"Oznámení je zavřeno."</string>
@@ -311,8 +313,7 @@
<string name="recents_search_bar_label" msgid="8074997400187836677">"vyhledat"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"Aplikaci <xliff:g id="APP">%s</xliff:g> nelze spustit."</string>
<string name="recents_launch_disabled_message" msgid="1624523193008871793">"Aplikace <xliff:g id="APP">%s</xliff:g> je v nouzovém režimu zakázána."</string>
- <string name="recents_history_button_label" msgid="5153358867807604821">"Historie"</string>
- <string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Vymazat"</string>
+ <string name="recents_stack_action_button_label" msgid="6593727103310426253">"Vymazat vše"</string>
<string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"Tato aplikace režim v několika oknech nepodporuje"</string>
<string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"Aplikace režim v několika oknech nepodporuje"</string>
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Vodorovné rozdělení"</string>
@@ -501,10 +502,48 @@
<string name="battery_detail_charging_summary" msgid="1279095653533044008">"Spořič baterie při nabíjení není k dispozici."</string>
<string name="battery_detail_switch_title" msgid="6285872470260795421">"Spořič baterie"</string>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"Omezuje výkon a data na pozadí"</string>
+ <string name="keyboard_key_button_template" msgid="6230056639734377300">"Tlačítko <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="keyboard_key_home" msgid="2243500072071305073">"Home"</string>
+ <string name="keyboard_key_back" msgid="2337450286042721351">"Zpět"</string>
+ <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"Nahoru"</string>
+ <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"Dolů"</string>
+ <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"Vlevo"</string>
+ <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"Vpravo"</string>
+ <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"Střed"</string>
+ <string name="keyboard_key_tab" msgid="3871485650463164476">"Tabulátor"</string>
+ <string name="keyboard_key_space" msgid="2499861316311153293">"Mezerník"</string>
+ <string name="keyboard_key_enter" msgid="5739632123216118137">"Enter"</string>
+ <string name="keyboard_key_backspace" msgid="1559580097512385854">"Backspace"</string>
+ <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"Přehrát/Pozastavit"</string>
+ <string name="keyboard_key_media_stop" msgid="2859963958595908962">"Zastavit"</string>
+ <string name="keyboard_key_media_next" msgid="1894394911630345607">"Další"</string>
+ <string name="keyboard_key_media_previous" msgid="4256072387192967261">"Předchozí"</string>
+ <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"Přetočit zpět"</string>
+ <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"Přetočit vpřed"</string>
+ <string name="keyboard_key_page_up" msgid="5654098530106845603">"Page Up"</string>
+ <string name="keyboard_key_page_down" msgid="8720502083731906136">"Page Down"</string>
+ <string name="keyboard_key_forward_del" msgid="1391451334716490176">"Delete"</string>
+ <string name="keyboard_key_move_home" msgid="2765693292069487486">"Home"</string>
+ <string name="keyboard_key_move_end" msgid="5901174332047975247">"End"</string>
+ <string name="keyboard_key_insert" msgid="8530501581636082614">"Insert"</string>
+ <string name="keyboard_key_num_lock" msgid="5052537581246772117">"Num Lock"</string>
+ <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"<xliff:g id="NAME">%1$s</xliff:g> na numerické klávesnici"</string>
<string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"Systém"</string>
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Plocha"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Poslední"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Zpět"</string>
+ <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Oznámení"</string>
+ <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"Klávesové zkratky"</string>
+ <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"Přepnout metodu zadávání"</string>
+ <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"Aplikace"</string>
+ <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"Asistence"</string>
+ <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"Prohlížeč"</string>
+ <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"Kontakty"</string>
+ <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"E-mail"</string>
+ <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"Chat"</string>
+ <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"Hudba"</string>
+ <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+ <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"Kalendář"</string>
<string name="tuner_full_zen_title" msgid="4540823317772234308">"Zobrazit včetně ovládacích prvků hlasitosti"</string>
<string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Nerušit"</string>
<string name="volume_dnd_silent" msgid="4363882330723050727">"Zkratka tlačítek hlasitosti"</string>
@@ -559,4 +598,14 @@
<string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Přesunout nahoru"</string>
<string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Přesunout vlevo"</string>
<string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Přesunout vpravo"</string>
+ <string name="forced_resizable_info_text" msgid="7591061837558867999">"Aplikace nemusí v režimu několika oken fungovat."</string>
+ <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"Pozice <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>. Dvojitým klepnutím ji upravíte."</string>
+ <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. Dlaždici přidáte dvojitým klepnutím."</string>
+ <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"Pozice <xliff:g id="POSITION">%1$d</xliff:g>. Dvojitým klepnutím ji vyberete."</string>
+ <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"Přesunout dlaždici <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"Odstranit dlaždici <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"Dlaždice <xliff:g id="TILE_NAME">%1$s</xliff:g> byla přidána na pozici <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+ <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"Dlaždice <xliff:g id="TILE_NAME">%1$s</xliff:g> byla odstraněna"</string>
+ <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"Dlaždice <xliff:g id="TILE_NAME">%1$s</xliff:g> byla přesunuta na pozici <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+ <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Editor rychlého nastavení"</string>
</resources>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index 0538bdb..7a25141 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -168,6 +168,8 @@
<string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Afvis <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> er annulleret."</string>
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Alle de seneste applikationer er lukket."</string>
+ <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+ <skip />
<string name="accessibility_recents_item_launched" msgid="7616039892382525203">"<xliff:g id="APP">%s</xliff:g> startes."</string>
<string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
<string name="accessibility_notification_dismissed" msgid="854211387186306927">"Underretningen er annulleret."</string>
@@ -236,8 +238,7 @@
<string name="gps_notification_found_text" msgid="4619274244146446464">"Placeringen er angivet ved hjælp af GPS"</string>
<string name="accessibility_location_active" msgid="2427290146138169014">"Aktive placeringsanmodninger"</string>
<string name="accessibility_clear_all" msgid="5235938559247164925">"Ryd alle underretninger."</string>
- <!-- no translation found for notification_group_overflow_indicator (1863231301642314183) -->
- <skip />
+ <string name="notification_group_overflow_indicator" msgid="1863231301642314183">"<xliff:g id="NUMBER">%s</xliff:g> mere"</string>
<string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"Underretningsindstillinger"</string>
<string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"Indstillinger for <xliff:g id="APP_NAME">%s</xliff:g>"</string>
<string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Skærmen roterer automatisk."</string>
@@ -310,8 +311,7 @@
<string name="recents_search_bar_label" msgid="8074997400187836677">"søg"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g> kunne ikke startes."</string>
<string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g> er deaktiveret i sikker tilstand."</string>
- <string name="recents_history_button_label" msgid="5153358867807604821">"Historik"</string>
- <string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Ryd"</string>
+ <string name="recents_stack_action_button_label" msgid="6593727103310426253">"Ryd alle"</string>
<string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"Denne app understøtter ikke flere vinduer"</string>
<string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"Appen understøtter ikke flere vinduer"</string>
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Opdel vandret"</string>
@@ -480,8 +480,7 @@
<string name="notification_importance_max" msgid="5806278962376556491">"Vis øverst på listen over underretninger, vis på skærmen, og tillad lyd"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Flere indstillinger"</string>
<string name="notification_done" msgid="5279426047273930175">"Færdig"</string>
- <!-- no translation found for notification_gear_accessibility (94429150213089611) -->
- <skip />
+ <string name="notification_gear_accessibility" msgid="94429150213089611">"Kontrolelementer til underretninger for <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="color_and_appearance" msgid="1254323855964993144">"Farve og udseende"</string>
<string name="night_mode" msgid="3540405868248625488">"Nattilstand"</string>
<string name="calibrate_display" msgid="5974642573432039217">"Kalibrer skærmen"</string>
@@ -501,10 +500,48 @@
<string name="battery_detail_charging_summary" msgid="1279095653533044008">"Batterisparefunktionen er ikke tilgængelig under opladning"</string>
<string name="battery_detail_switch_title" msgid="6285872470260795421">"Batterisparefunktion"</string>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"Reducerer ydeevne og baggrundsdata"</string>
+ <string name="keyboard_key_button_template" msgid="6230056639734377300">"<xliff:g id="NAME">%1$s</xliff:g>-knap"</string>
+ <string name="keyboard_key_home" msgid="2243500072071305073">"Home"</string>
+ <string name="keyboard_key_back" msgid="2337450286042721351">"Tilbage"</string>
+ <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"Op"</string>
+ <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"Ned"</string>
+ <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"Venstre"</string>
+ <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"Højre"</string>
+ <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"Midtertast"</string>
+ <string name="keyboard_key_tab" msgid="3871485650463164476">"Tabulatortast"</string>
+ <string name="keyboard_key_space" msgid="2499861316311153293">"Mellemrumstast"</string>
+ <string name="keyboard_key_enter" msgid="5739632123216118137">"Enter"</string>
+ <string name="keyboard_key_backspace" msgid="1559580097512385854">"Tilbagetast"</string>
+ <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"Afspil/pause"</string>
+ <string name="keyboard_key_media_stop" msgid="2859963958595908962">"Stop"</string>
+ <string name="keyboard_key_media_next" msgid="1894394911630345607">"Næste"</string>
+ <string name="keyboard_key_media_previous" msgid="4256072387192967261">"Forrige"</string>
+ <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"Spol tilbage"</string>
+ <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"Spol frem"</string>
+ <string name="keyboard_key_page_up" msgid="5654098530106845603">"Page Up"</string>
+ <string name="keyboard_key_page_down" msgid="8720502083731906136">"Page Down"</string>
+ <string name="keyboard_key_forward_del" msgid="1391451334716490176">"Delete"</string>
+ <string name="keyboard_key_move_home" msgid="2765693292069487486">"Home"</string>
+ <string name="keyboard_key_move_end" msgid="5901174332047975247">"End"</string>
+ <string name="keyboard_key_insert" msgid="8530501581636082614">"Insert"</string>
+ <string name="keyboard_key_num_lock" msgid="5052537581246772117">"Num Lock"</string>
+ <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"Numerisk tastatur <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"System"</string>
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Start"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Seneste"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Tilbage"</string>
+ <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Underretninger"</string>
+ <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"Tastaturgenveje"</string>
+ <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"Skift indtastningsmetode"</string>
+ <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"Applikationer"</string>
+ <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"Assistance"</string>
+ <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"Browser"</string>
+ <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"Kontaktpersoner"</string>
+ <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"E-mail"</string>
+ <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"Chat"</string>
+ <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"Musik"</string>
+ <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+ <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"Kalender"</string>
<string name="tuner_full_zen_title" msgid="4540823317772234308">"Vis med lydstyrkeregulering"</string>
<string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Forstyr ikke"</string>
<string name="volume_dnd_silent" msgid="4363882330723050727">"Genvej til lydstyrkeknapper"</string>
@@ -559,4 +596,14 @@
<string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Flyt op"</string>
<string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Flyt til venstre"</string>
<string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Flyt til højre"</string>
+ <string name="forced_resizable_info_text" msgid="7591061837558867999">"Appen fungerer muligvis ikke i Multivindue"</string>
+ <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"Position <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>. Tryk to gange for at redigere."</string>
+ <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. Tryk to gange for at tilføje."</string>
+ <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"Position <xliff:g id="POSITION">%1$d</xliff:g>. Tryk to gange for at vælge."</string>
+ <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"Flyt <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"Fjern <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="TILE_NAME">%1$s</xliff:g> føjes til position <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+ <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"<xliff:g id="TILE_NAME">%1$s</xliff:g> fjernes"</string>
+ <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="TILE_NAME">%1$s</xliff:g> blev flyttet til position <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+ <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Redigeringsværktøj for Hurtige indstillinger."</string>
</resources>
diff --git a/packages/SystemUI/res/values-da/strings_tv.xml b/packages/SystemUI/res/values-da/strings_tv.xml
index 51b8582..45bba75 100644
--- a/packages/SystemUI/res/values-da/strings_tv.xml
+++ b/packages/SystemUI/res/values-da/strings_tv.xml
@@ -26,6 +26,5 @@
<string name="pip_hold_home" msgid="340086535668778109">"Hold "<b>"HOME"</b>" nede for at styre PIP"</string>
<string name="pip_onboarding_description" msgid="2882896641362814195">"Tryk på HOME-knappen, og hold den nede for at styre PIP"</string>
<string name="pip_onboarding_button" msgid="3957426748484904611">"OK"</string>
- <!-- no translation found for recents_tv_dismiss (3555093879593377731) -->
- <skip />
+ <string name="recents_tv_dismiss" msgid="3555093879593377731">"Afvis"</string>
</resources>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index 4cd0316..e10eb64 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -168,6 +168,8 @@
<string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"<xliff:g id="APP">%s</xliff:g> beenden"</string>
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> entfernt"</string>
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Alle kürzlich verwendeten Apps wurden entfernt."</string>
+ <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+ <skip />
<string name="accessibility_recents_item_launched" msgid="7616039892382525203">"<xliff:g id="APP">%s</xliff:g> wird gestartet."</string>
<string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
<string name="accessibility_notification_dismissed" msgid="854211387186306927">"Benachrichtigung geschlossen"</string>
@@ -236,8 +238,7 @@
<string name="gps_notification_found_text" msgid="4619274244146446464">"Standort durch GPS festgelegt"</string>
<string name="accessibility_location_active" msgid="2427290146138169014">"Standortanfragen aktiv"</string>
<string name="accessibility_clear_all" msgid="5235938559247164925">"Alle Benachrichtigungen löschen"</string>
- <!-- no translation found for notification_group_overflow_indicator (1863231301642314183) -->
- <skip />
+ <string name="notification_group_overflow_indicator" msgid="1863231301642314183">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string>
<string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"Benachrichtigungseinstellungen"</string>
<string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"Einstellungen von <xliff:g id="APP_NAME">%s</xliff:g>"</string>
<string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Bildschirm wird automatisch gedreht."</string>
@@ -310,8 +311,7 @@
<string name="recents_search_bar_label" msgid="8074997400187836677">"Suche"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g> konnte nicht gestartet werden."</string>
<string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g> ist im abgesicherten Modus deaktiviert."</string>
- <string name="recents_history_button_label" msgid="5153358867807604821">"Verlauf"</string>
- <string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Löschen"</string>
+ <string name="recents_stack_action_button_label" msgid="6593727103310426253">"Alle löschen"</string>
<string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"Diese App unterstützt den Mehrfenstermodus nicht"</string>
<string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"App unterstützt Mehrfenstermodus nicht"</string>
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Geteilte Schaltfläche – horizontal"</string>
@@ -480,8 +480,7 @@
<string name="notification_importance_max" msgid="5806278962376556491">"Ganz oben in der Benachrichtigungsliste anzeigen, auf dem Display einblenden und Ton zulassen"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Weitere Einstellungen"</string>
<string name="notification_done" msgid="5279426047273930175">"Fertig"</string>
- <!-- no translation found for notification_gear_accessibility (94429150213089611) -->
- <skip />
+ <string name="notification_gear_accessibility" msgid="94429150213089611">"<xliff:g id="APP_NAME">%1$s</xliff:g>-Benachrichtigungseinstellungen"</string>
<string name="color_and_appearance" msgid="1254323855964993144">"Farbe und Darstellung"</string>
<string name="night_mode" msgid="3540405868248625488">"Nachtmodus"</string>
<string name="calibrate_display" msgid="5974642573432039217">"Bildschirm kalibrieren"</string>
@@ -501,10 +500,48 @@
<string name="battery_detail_charging_summary" msgid="1279095653533044008">"Der Energiesparmodus ist beim Aufladen nicht verfügbar."</string>
<string name="battery_detail_switch_title" msgid="6285872470260795421">"Energiesparmodus"</string>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"Reduzierung der Leistung und Hintergrunddaten"</string>
+ <string name="keyboard_key_button_template" msgid="6230056639734377300">"Taste <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="keyboard_key_home" msgid="2243500072071305073">"Pos1"</string>
+ <string name="keyboard_key_back" msgid="2337450286042721351">"Zurück"</string>
+ <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"Nach oben"</string>
+ <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"Nach unten"</string>
+ <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"Nach links"</string>
+ <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"Nach rechts"</string>
+ <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"Zentrieren"</string>
+ <string name="keyboard_key_tab" msgid="3871485650463164476">"Tabulatortaste"</string>
+ <string name="keyboard_key_space" msgid="2499861316311153293">"Leertaste"</string>
+ <string name="keyboard_key_enter" msgid="5739632123216118137">"Eingabetaste"</string>
+ <string name="keyboard_key_backspace" msgid="1559580097512385854">"Rücktaste"</string>
+ <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"Wiedergabe/Pause"</string>
+ <string name="keyboard_key_media_stop" msgid="2859963958595908962">"Stopp"</string>
+ <string name="keyboard_key_media_next" msgid="1894394911630345607">"Weiter"</string>
+ <string name="keyboard_key_media_previous" msgid="4256072387192967261">"Zurück"</string>
+ <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"Zurückspulen"</string>
+ <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"Vorspulen"</string>
+ <string name="keyboard_key_page_up" msgid="5654098530106845603">"Nach oben"</string>
+ <string name="keyboard_key_page_down" msgid="8720502083731906136">"Nach unten"</string>
+ <string name="keyboard_key_forward_del" msgid="1391451334716490176">"Entf"</string>
+ <string name="keyboard_key_move_home" msgid="2765693292069487486">"Pos1"</string>
+ <string name="keyboard_key_move_end" msgid="5901174332047975247">"Ende"</string>
+ <string name="keyboard_key_insert" msgid="8530501581636082614">"Einfg"</string>
+ <string name="keyboard_key_num_lock" msgid="5052537581246772117">"Num"</string>
+ <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"Ziffernblock <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"System"</string>
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Startseite"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Letzte"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Zurück"</string>
+ <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Benachrichtigungen"</string>
+ <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"Tastenkombinationen"</string>
+ <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"Eingabemethode wechseln"</string>
+ <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"Apps"</string>
+ <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"Assistent"</string>
+ <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"Browser"</string>
+ <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"Kontakte"</string>
+ <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"E-Mail"</string>
+ <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"IM"</string>
+ <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"Music"</string>
+ <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+ <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"Kalender"</string>
<string name="tuner_full_zen_title" msgid="4540823317772234308">"Einschließlich Lautstärkeregler anzeigen"</string>
<string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Bitte nicht stören"</string>
<string name="volume_dnd_silent" msgid="4363882330723050727">"Tastenkombination für Lautstärketasten"</string>
@@ -559,4 +596,14 @@
<string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Nach oben verschieben"</string>
<string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Nach links verschieben"</string>
<string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Nach rechts verschieben"</string>
+ <string name="forced_resizable_info_text" msgid="7591061837558867999">"App funktioniert im Mehrfenstermodus möglicherweise nicht"</string>
+ <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"Position <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>. Zum Bearbeiten doppeltippen."</string>
+ <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. Zum Hinzufügen doppeltippen."</string>
+ <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"Position <xliff:g id="POSITION">%1$d</xliff:g>. Zum Auswählen doppeltippen."</string>
+ <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"<xliff:g id="TILE_NAME">%1$s</xliff:g> verschieben"</string>
+ <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"<xliff:g id="TILE_NAME">%1$s</xliff:g> entfernen"</string>
+ <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="TILE_NAME">%1$s</xliff:g> ist auf Position <xliff:g id="POSITION">%2$d</xliff:g> hinzugefügt worden"</string>
+ <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"<xliff:g id="TILE_NAME">%1$s</xliff:g> wurde entfernt"</string>
+ <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="TILE_NAME">%1$s</xliff:g> an Position <xliff:g id="POSITION">%2$d</xliff:g> verschoben"</string>
+ <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Editor für Schnelleinstellungen."</string>
</resources>
diff --git a/packages/SystemUI/res/values-de/strings_tv.xml b/packages/SystemUI/res/values-de/strings_tv.xml
index f448737..3d9c233 100644
--- a/packages/SystemUI/res/values-de/strings_tv.xml
+++ b/packages/SystemUI/res/values-de/strings_tv.xml
@@ -26,6 +26,5 @@
<string name="pip_hold_home" msgid="340086535668778109"><b>"STARTBILDSCHIRMTASTE"</b>" drücken, um PIP zu steuern"</string>
<string name="pip_onboarding_description" msgid="2882896641362814195">"Halte die Taste für die Startseite gedrückt, um das Bild-in-Bild zu steuern"</string>
<string name="pip_onboarding_button" msgid="3957426748484904611">"OK"</string>
- <!-- no translation found for recents_tv_dismiss (3555093879593377731) -->
- <skip />
+ <string name="recents_tv_dismiss" msgid="3555093879593377731">"Beenden"</string>
</resources>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index 59810c2..5ec3133 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -168,6 +168,8 @@
<string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Παράβλεψη <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"Απορρίφθηκαν <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Έγινε παράβλεψη όλων των πρόσφατων εφαρμογών."</string>
+ <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+ <skip />
<string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Έναρξη <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
<string name="accessibility_notification_dismissed" msgid="854211387186306927">"Η ειδοποίηση έχει απορριφθεί."</string>
@@ -236,8 +238,7 @@
<string name="gps_notification_found_text" msgid="4619274244146446464">"Ρύθμιση τοποθεσίας με GPS"</string>
<string name="accessibility_location_active" msgid="2427290146138169014">"Τα αιτήματα τοποθεσίας έχουν ενεργοποιηθεί"</string>
<string name="accessibility_clear_all" msgid="5235938559247164925">"Εκκαθάριση όλων των ειδοποιήσεων."</string>
- <!-- no translation found for notification_group_overflow_indicator (1863231301642314183) -->
- <skip />
+ <string name="notification_group_overflow_indicator" msgid="1863231301642314183">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string>
<string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"Ρυθμίσεις ειδοποιήσεων"</string>
<string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"Ρυθμίσεις <xliff:g id="APP_NAME">%s</xliff:g>"</string>
<string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Θα γίνεται αυτόματη περιστροφή της οθόνης."</string>
@@ -310,8 +311,7 @@
<string name="recents_search_bar_label" msgid="8074997400187836677">"αναζήτηση"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"Δεν ήταν δυνατή η εκκίνηση της εφαρμογής <xliff:g id="APP">%s</xliff:g>."</string>
<string name="recents_launch_disabled_message" msgid="1624523193008871793">"Η εφαρμογή <xliff:g id="APP">%s</xliff:g> έχει απενεργοποιηθεί στην ασφαλή λειτουργία."</string>
- <string name="recents_history_button_label" msgid="5153358867807604821">"Ιστορικό"</string>
- <string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Εκκαθάριση"</string>
+ <string name="recents_stack_action_button_label" msgid="6593727103310426253">"Διαγραφή όλων"</string>
<string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"Η εφαρμογή αυτή δεν υποστηρίζει τη λειτουργία πολλαπλών παραθύρων"</string>
<string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"Η εφαρμογή δεν υποστηρίζει τη λειτουργία πολλαπλών παραθύρων"</string>
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Οριζόντιος διαχωρισμός"</string>
@@ -480,8 +480,7 @@
<string name="notification_importance_max" msgid="5806278962376556491">"Να εμφανίζονται στην κορυφή της λίστας ειδοποιήσεων, να προβάλλονται στην οθόνη και να επιτρέπεται ο ήχος"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Περισσότερες ρυθμίσεις"</string>
<string name="notification_done" msgid="5279426047273930175">"Τέλος"</string>
- <!-- no translation found for notification_gear_accessibility (94429150213089611) -->
- <skip />
+ <string name="notification_gear_accessibility" msgid="94429150213089611">"Στοιχεία ελέγχου κοινοποίησης <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="color_and_appearance" msgid="1254323855964993144">"Χρώμα και εμφάνιση"</string>
<string name="night_mode" msgid="3540405868248625488">"Νυχτερινή λειτουργία"</string>
<string name="calibrate_display" msgid="5974642573432039217">"Βαθμονόμηση οθόνης"</string>
@@ -501,10 +500,48 @@
<string name="battery_detail_charging_summary" msgid="1279095653533044008">"Η εξοικονόμηση μπαταρίας δεν είναι διαθέσιμη κατά τη διάρκεια της φόρτισης"</string>
<string name="battery_detail_switch_title" msgid="6285872470260795421">"Εξοικονόμηση μπαταρίας"</string>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"Μειώνει την απόδοση και τα δεδομένα παρασκηνίου"</string>
+ <string name="keyboard_key_button_template" msgid="6230056639734377300">"Κουμπί <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="keyboard_key_home" msgid="2243500072071305073">"Home"</string>
+ <string name="keyboard_key_back" msgid="2337450286042721351">"Πίσω"</string>
+ <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"Πάνω"</string>
+ <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"Κάτω"</string>
+ <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"Αριστερά"</string>
+ <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"Δεξιά"</string>
+ <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"Κέντρο"</string>
+ <string name="keyboard_key_tab" msgid="3871485650463164476">"Tab"</string>
+ <string name="keyboard_key_space" msgid="2499861316311153293">"Πλήκτρο διαστήματος"</string>
+ <string name="keyboard_key_enter" msgid="5739632123216118137">"Enter"</string>
+ <string name="keyboard_key_backspace" msgid="1559580097512385854">"Backspace"</string>
+ <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"Αναπαραγωγή/Παύση"</string>
+ <string name="keyboard_key_media_stop" msgid="2859963958595908962">"Διακοπή"</string>
+ <string name="keyboard_key_media_next" msgid="1894394911630345607">"Επόμενο"</string>
+ <string name="keyboard_key_media_previous" msgid="4256072387192967261">"Προηγούμενο"</string>
+ <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"Επαναφορά"</string>
+ <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"Γρήγορη προώθηση"</string>
+ <string name="keyboard_key_page_up" msgid="5654098530106845603">"Προηγούμενη σελίδα"</string>
+ <string name="keyboard_key_page_down" msgid="8720502083731906136">"Επόμενη σελίδα"</string>
+ <string name="keyboard_key_forward_del" msgid="1391451334716490176">"Delete"</string>
+ <string name="keyboard_key_move_home" msgid="2765693292069487486">"Home"</string>
+ <string name="keyboard_key_move_end" msgid="5901174332047975247">"Λήξη"</string>
+ <string name="keyboard_key_insert" msgid="8530501581636082614">"Insert"</string>
+ <string name="keyboard_key_num_lock" msgid="5052537581246772117">"Num Lock"</string>
+ <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"Αριθμητικό πληκτρολόγιο <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"Σύστημα"</string>
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Αρχική οθόνη"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Πρόσφατα"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Πίσω"</string>
+ <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Ειδοποιήσεις"</string>
+ <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"Συντομεύσεις πληκτρολογίου"</string>
+ <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"Εναλλαγή μεθόδου εισαγωγής"</string>
+ <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"Εφαρμογές"</string>
+ <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"Υποβοήθηση"</string>
+ <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"Πρόγραμμα περιήγησης"</string>
+ <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"Επαφές"</string>
+ <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"Ηλεκτρονικό ταχυδρομείο"</string>
+ <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"Άμεσα μηνύματα (ΙΜ)"</string>
+ <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"Μουσική"</string>
+ <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+ <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"Ημερολόγιο"</string>
<string name="tuner_full_zen_title" msgid="4540823317772234308">"Εμφάνιση με στοιχεία ελέγχου έντασης ήχου"</string>
<string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Μην ενοχλείτε"</string>
<string name="volume_dnd_silent" msgid="4363882330723050727">"Συντόμευση κουμπιών έντασης ήχου"</string>
@@ -559,4 +596,14 @@
<string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Μετακίνηση προς τα επάνω"</string>
<string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Μετακίνηση αριστερά"</string>
<string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Μετακίνηση δεξιά"</string>
+ <string name="forced_resizable_info_text" msgid="7591061837558867999">"Η εφαρμογή ενδέχεται να μη λειτουργεί με τη λειτουργία πολλαπλών παραθύρων"</string>
+ <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"Θέση <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>. Πατήστε δύο φορές για επεξεργασία."</string>
+ <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. Πατήστε δύο φορές για προσθήκη."</string>
+ <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"Θέση <xliff:g id="POSITION">%1$d</xliff:g>. Πατήστε δύο φορές για επιλογή."</string>
+ <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"Μετακίνηση <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"Κατάργηση <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"Το <xliff:g id="TILE_NAME">%1$s</xliff:g> προστέθηκε στη θέση <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+ <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"Το <xliff:g id="TILE_NAME">%1$s</xliff:g> καταργείται"</string>
+ <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"Το <xliff:g id="TILE_NAME">%1$s</xliff:g> μετακινήθηκε στη θέση <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+ <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Επεξεργασία γρήγορων ρυθμίσεων."</string>
</resources>
diff --git a/packages/SystemUI/res/values-el/strings_tv.xml b/packages/SystemUI/res/values-el/strings_tv.xml
index 355c9b0..c54c7be 100644
--- a/packages/SystemUI/res/values-el/strings_tv.xml
+++ b/packages/SystemUI/res/values-el/strings_tv.xml
@@ -26,6 +26,5 @@
<string name="pip_hold_home" msgid="340086535668778109">"Κρατήστε το πλήκτρο "<b>"HOME"</b>" πατημένο για έλεγχο του PIP"</string>
<string name="pip_onboarding_description" msgid="2882896641362814195">"Πιέστε παρατεταμένα το κουμπί HOME, για να ελέγξετε τη λειτουργία PIP"</string>
<string name="pip_onboarding_button" msgid="3957426748484904611">"Κατάλαβα"</string>
- <!-- no translation found for recents_tv_dismiss (3555093879593377731) -->
- <skip />
+ <string name="recents_tv_dismiss" msgid="3555093879593377731">"Παράβλεψη"</string>
</resources>
diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml
index 9346188..f08894f 100644
--- a/packages/SystemUI/res/values-en-rAU/strings.xml
+++ b/packages/SystemUI/res/values-en-rAU/strings.xml
@@ -168,6 +168,8 @@
<string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Dismiss <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> dismissed."</string>
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"All recent applications dismissed."</string>
+ <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+ <skip />
<string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Starting <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
<string name="accessibility_notification_dismissed" msgid="854211387186306927">"Notification dismissed."</string>
@@ -309,8 +311,7 @@
<string name="recents_search_bar_label" msgid="8074997400187836677">"search"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"Could not start <xliff:g id="APP">%s</xliff:g>."</string>
<string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g> is disabled in safe-mode."</string>
- <string name="recents_history_button_label" msgid="5153358867807604821">"History"</string>
- <string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Clear"</string>
+ <string name="recents_stack_action_button_label" msgid="6593727103310426253">"Clear all"</string>
<string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"This app does not support multi-window"</string>
<string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"App does not support multi-window"</string>
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Split Horizontal"</string>
@@ -499,10 +500,48 @@
<string name="battery_detail_charging_summary" msgid="1279095653533044008">"Battery Saver not available during charging"</string>
<string name="battery_detail_switch_title" msgid="6285872470260795421">"Battery Saver"</string>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"Reduces performance and background data"</string>
+ <string name="keyboard_key_button_template" msgid="6230056639734377300">"Button <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="keyboard_key_home" msgid="2243500072071305073">"Home"</string>
+ <string name="keyboard_key_back" msgid="2337450286042721351">"Back"</string>
+ <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"Up"</string>
+ <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"Down"</string>
+ <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"Left"</string>
+ <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"Right"</string>
+ <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"Centre"</string>
+ <string name="keyboard_key_tab" msgid="3871485650463164476">"Tab"</string>
+ <string name="keyboard_key_space" msgid="2499861316311153293">"Space"</string>
+ <string name="keyboard_key_enter" msgid="5739632123216118137">"Enter"</string>
+ <string name="keyboard_key_backspace" msgid="1559580097512385854">"Backspace"</string>
+ <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"Play/Pause"</string>
+ <string name="keyboard_key_media_stop" msgid="2859963958595908962">"Stop"</string>
+ <string name="keyboard_key_media_next" msgid="1894394911630345607">"Next"</string>
+ <string name="keyboard_key_media_previous" msgid="4256072387192967261">"Previous"</string>
+ <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"Rewind"</string>
+ <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"Fast-Forward"</string>
+ <string name="keyboard_key_page_up" msgid="5654098530106845603">"Page Up"</string>
+ <string name="keyboard_key_page_down" msgid="8720502083731906136">"Page Down"</string>
+ <string name="keyboard_key_forward_del" msgid="1391451334716490176">"Delete"</string>
+ <string name="keyboard_key_move_home" msgid="2765693292069487486">"Home"</string>
+ <string name="keyboard_key_move_end" msgid="5901174332047975247">"End"</string>
+ <string name="keyboard_key_insert" msgid="8530501581636082614">"Insert"</string>
+ <string name="keyboard_key_num_lock" msgid="5052537581246772117">"Num Lock"</string>
+ <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"Numpad <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"System"</string>
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Home"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Recent"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Back"</string>
+ <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Notifications"</string>
+ <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"Keyboard Shortcuts"</string>
+ <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"Switch input method"</string>
+ <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"Applications"</string>
+ <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"Assist"</string>
+ <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"Browser"</string>
+ <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"Contacts"</string>
+ <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"Email"</string>
+ <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"IM"</string>
+ <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"Music"</string>
+ <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+ <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"Calendar"</string>
<string name="tuner_full_zen_title" msgid="4540823317772234308">"Show with volume controls"</string>
<string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Do not disturb"</string>
<string name="volume_dnd_silent" msgid="4363882330723050727">"Volume buttons shortcut"</string>
@@ -557,4 +596,14 @@
<string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Move up"</string>
<string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Move to the left"</string>
<string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Move to the right"</string>
+ <string name="forced_resizable_info_text" msgid="7591061837558867999">"App may not work with multi-window"</string>
+ <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"Position <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>. Double tap to edit."</string>
+ <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. Double tap to add."</string>
+ <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"Position <xliff:g id="POSITION">%1$d</xliff:g>. Double tap to select."</string>
+ <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"Move <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"Remove <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="TILE_NAME">%1$s</xliff:g> is added to position <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+ <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"<xliff:g id="TILE_NAME">%1$s</xliff:g> is removed"</string>
+ <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="TILE_NAME">%1$s</xliff:g> moved to position <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+ <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Quick settings editor."</string>
</resources>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index 9346188..f08894f 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -168,6 +168,8 @@
<string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Dismiss <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> dismissed."</string>
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"All recent applications dismissed."</string>
+ <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+ <skip />
<string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Starting <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
<string name="accessibility_notification_dismissed" msgid="854211387186306927">"Notification dismissed."</string>
@@ -309,8 +311,7 @@
<string name="recents_search_bar_label" msgid="8074997400187836677">"search"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"Could not start <xliff:g id="APP">%s</xliff:g>."</string>
<string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g> is disabled in safe-mode."</string>
- <string name="recents_history_button_label" msgid="5153358867807604821">"History"</string>
- <string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Clear"</string>
+ <string name="recents_stack_action_button_label" msgid="6593727103310426253">"Clear all"</string>
<string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"This app does not support multi-window"</string>
<string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"App does not support multi-window"</string>
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Split Horizontal"</string>
@@ -499,10 +500,48 @@
<string name="battery_detail_charging_summary" msgid="1279095653533044008">"Battery Saver not available during charging"</string>
<string name="battery_detail_switch_title" msgid="6285872470260795421">"Battery Saver"</string>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"Reduces performance and background data"</string>
+ <string name="keyboard_key_button_template" msgid="6230056639734377300">"Button <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="keyboard_key_home" msgid="2243500072071305073">"Home"</string>
+ <string name="keyboard_key_back" msgid="2337450286042721351">"Back"</string>
+ <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"Up"</string>
+ <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"Down"</string>
+ <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"Left"</string>
+ <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"Right"</string>
+ <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"Centre"</string>
+ <string name="keyboard_key_tab" msgid="3871485650463164476">"Tab"</string>
+ <string name="keyboard_key_space" msgid="2499861316311153293">"Space"</string>
+ <string name="keyboard_key_enter" msgid="5739632123216118137">"Enter"</string>
+ <string name="keyboard_key_backspace" msgid="1559580097512385854">"Backspace"</string>
+ <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"Play/Pause"</string>
+ <string name="keyboard_key_media_stop" msgid="2859963958595908962">"Stop"</string>
+ <string name="keyboard_key_media_next" msgid="1894394911630345607">"Next"</string>
+ <string name="keyboard_key_media_previous" msgid="4256072387192967261">"Previous"</string>
+ <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"Rewind"</string>
+ <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"Fast-Forward"</string>
+ <string name="keyboard_key_page_up" msgid="5654098530106845603">"Page Up"</string>
+ <string name="keyboard_key_page_down" msgid="8720502083731906136">"Page Down"</string>
+ <string name="keyboard_key_forward_del" msgid="1391451334716490176">"Delete"</string>
+ <string name="keyboard_key_move_home" msgid="2765693292069487486">"Home"</string>
+ <string name="keyboard_key_move_end" msgid="5901174332047975247">"End"</string>
+ <string name="keyboard_key_insert" msgid="8530501581636082614">"Insert"</string>
+ <string name="keyboard_key_num_lock" msgid="5052537581246772117">"Num Lock"</string>
+ <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"Numpad <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"System"</string>
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Home"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Recent"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Back"</string>
+ <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Notifications"</string>
+ <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"Keyboard Shortcuts"</string>
+ <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"Switch input method"</string>
+ <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"Applications"</string>
+ <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"Assist"</string>
+ <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"Browser"</string>
+ <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"Contacts"</string>
+ <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"Email"</string>
+ <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"IM"</string>
+ <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"Music"</string>
+ <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+ <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"Calendar"</string>
<string name="tuner_full_zen_title" msgid="4540823317772234308">"Show with volume controls"</string>
<string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Do not disturb"</string>
<string name="volume_dnd_silent" msgid="4363882330723050727">"Volume buttons shortcut"</string>
@@ -557,4 +596,14 @@
<string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Move up"</string>
<string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Move to the left"</string>
<string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Move to the right"</string>
+ <string name="forced_resizable_info_text" msgid="7591061837558867999">"App may not work with multi-window"</string>
+ <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"Position <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>. Double tap to edit."</string>
+ <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. Double tap to add."</string>
+ <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"Position <xliff:g id="POSITION">%1$d</xliff:g>. Double tap to select."</string>
+ <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"Move <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"Remove <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="TILE_NAME">%1$s</xliff:g> is added to position <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+ <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"<xliff:g id="TILE_NAME">%1$s</xliff:g> is removed"</string>
+ <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="TILE_NAME">%1$s</xliff:g> moved to position <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+ <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Quick settings editor."</string>
</resources>
diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
index 9346188..f08894f 100644
--- a/packages/SystemUI/res/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings.xml
@@ -168,6 +168,8 @@
<string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Dismiss <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> dismissed."</string>
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"All recent applications dismissed."</string>
+ <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+ <skip />
<string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Starting <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
<string name="accessibility_notification_dismissed" msgid="854211387186306927">"Notification dismissed."</string>
@@ -309,8 +311,7 @@
<string name="recents_search_bar_label" msgid="8074997400187836677">"search"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"Could not start <xliff:g id="APP">%s</xliff:g>."</string>
<string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g> is disabled in safe-mode."</string>
- <string name="recents_history_button_label" msgid="5153358867807604821">"History"</string>
- <string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Clear"</string>
+ <string name="recents_stack_action_button_label" msgid="6593727103310426253">"Clear all"</string>
<string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"This app does not support multi-window"</string>
<string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"App does not support multi-window"</string>
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Split Horizontal"</string>
@@ -499,10 +500,48 @@
<string name="battery_detail_charging_summary" msgid="1279095653533044008">"Battery Saver not available during charging"</string>
<string name="battery_detail_switch_title" msgid="6285872470260795421">"Battery Saver"</string>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"Reduces performance and background data"</string>
+ <string name="keyboard_key_button_template" msgid="6230056639734377300">"Button <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="keyboard_key_home" msgid="2243500072071305073">"Home"</string>
+ <string name="keyboard_key_back" msgid="2337450286042721351">"Back"</string>
+ <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"Up"</string>
+ <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"Down"</string>
+ <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"Left"</string>
+ <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"Right"</string>
+ <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"Centre"</string>
+ <string name="keyboard_key_tab" msgid="3871485650463164476">"Tab"</string>
+ <string name="keyboard_key_space" msgid="2499861316311153293">"Space"</string>
+ <string name="keyboard_key_enter" msgid="5739632123216118137">"Enter"</string>
+ <string name="keyboard_key_backspace" msgid="1559580097512385854">"Backspace"</string>
+ <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"Play/Pause"</string>
+ <string name="keyboard_key_media_stop" msgid="2859963958595908962">"Stop"</string>
+ <string name="keyboard_key_media_next" msgid="1894394911630345607">"Next"</string>
+ <string name="keyboard_key_media_previous" msgid="4256072387192967261">"Previous"</string>
+ <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"Rewind"</string>
+ <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"Fast-Forward"</string>
+ <string name="keyboard_key_page_up" msgid="5654098530106845603">"Page Up"</string>
+ <string name="keyboard_key_page_down" msgid="8720502083731906136">"Page Down"</string>
+ <string name="keyboard_key_forward_del" msgid="1391451334716490176">"Delete"</string>
+ <string name="keyboard_key_move_home" msgid="2765693292069487486">"Home"</string>
+ <string name="keyboard_key_move_end" msgid="5901174332047975247">"End"</string>
+ <string name="keyboard_key_insert" msgid="8530501581636082614">"Insert"</string>
+ <string name="keyboard_key_num_lock" msgid="5052537581246772117">"Num Lock"</string>
+ <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"Numpad <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"System"</string>
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Home"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Recent"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Back"</string>
+ <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Notifications"</string>
+ <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"Keyboard Shortcuts"</string>
+ <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"Switch input method"</string>
+ <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"Applications"</string>
+ <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"Assist"</string>
+ <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"Browser"</string>
+ <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"Contacts"</string>
+ <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"Email"</string>
+ <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"IM"</string>
+ <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"Music"</string>
+ <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+ <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"Calendar"</string>
<string name="tuner_full_zen_title" msgid="4540823317772234308">"Show with volume controls"</string>
<string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Do not disturb"</string>
<string name="volume_dnd_silent" msgid="4363882330723050727">"Volume buttons shortcut"</string>
@@ -557,4 +596,14 @@
<string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Move up"</string>
<string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Move to the left"</string>
<string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Move to the right"</string>
+ <string name="forced_resizable_info_text" msgid="7591061837558867999">"App may not work with multi-window"</string>
+ <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"Position <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>. Double tap to edit."</string>
+ <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. Double tap to add."</string>
+ <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"Position <xliff:g id="POSITION">%1$d</xliff:g>. Double tap to select."</string>
+ <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"Move <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"Remove <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="TILE_NAME">%1$s</xliff:g> is added to position <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+ <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"<xliff:g id="TILE_NAME">%1$s</xliff:g> is removed"</string>
+ <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="TILE_NAME">%1$s</xliff:g> moved to position <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+ <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Quick settings editor."</string>
</resources>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index 45b4020..b5a10e1 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -168,6 +168,8 @@
<string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Rechazar <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> descartada."</string>
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Se descartaron todas las aplicaciones recientes."</string>
+ <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+ <skip />
<string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Iniciando <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
<string name="accessibility_notification_dismissed" msgid="854211387186306927">"Notificación ignorada"</string>
@@ -236,8 +238,7 @@
<string name="gps_notification_found_text" msgid="4619274244146446464">"La ubicación se estableció por GPS"</string>
<string name="accessibility_location_active" msgid="2427290146138169014">"Solicitudes de ubicación activas"</string>
<string name="accessibility_clear_all" msgid="5235938559247164925">"Eliminar todas las notificaciones"</string>
- <!-- no translation found for notification_group_overflow_indicator (1863231301642314183) -->
- <skip />
+ <string name="notification_group_overflow_indicator" msgid="1863231301642314183">"<xliff:g id="NUMBER">%s</xliff:g> más"</string>
<string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"Configuración de notificaciones"</string>
<string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"Configuración de <xliff:g id="APP_NAME">%s</xliff:g>"</string>
<string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"La pantalla girará automáticamente."</string>
@@ -304,14 +305,13 @@
<string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Advertencia de <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Modo de trabajo"</string>
<string name="recents_empty_message" msgid="808480104164008572">"No hay elementos recientes"</string>
- <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Borraste todo"</string>
+ <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Todo borrado"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Información de la aplicación"</string>
<string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"Fijar pantalla"</string>
<string name="recents_search_bar_label" msgid="8074997400187836677">"buscar"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"No se pudo iniciar <xliff:g id="APP">%s</xliff:g>."</string>
<string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g> está inhabilitada en modo seguro."</string>
- <string name="recents_history_button_label" msgid="5153358867807604821">"Historial"</string>
- <string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Borrar"</string>
+ <string name="recents_stack_action_button_label" msgid="6593727103310426253">"Borrar todo"</string>
<string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"Esta app no es compatible con el modo multiventana"</string>
<string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"La app no es compatible con el modo multiventana"</string>
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"División horizontal"</string>
@@ -480,8 +480,7 @@
<string name="notification_importance_max" msgid="5806278962376556491">"Mostrar en la parte superior de la lista de notificaciones, ver en la pantalla y permitir sonidos"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Más opciones de configuración"</string>
<string name="notification_done" msgid="5279426047273930175">"Listo"</string>
- <!-- no translation found for notification_gear_accessibility (94429150213089611) -->
- <skip />
+ <string name="notification_gear_accessibility" msgid="94429150213089611">"Controles de notificaciones de <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="color_and_appearance" msgid="1254323855964993144">"Color y apariencia"</string>
<string name="night_mode" msgid="3540405868248625488">"Modo nocturno"</string>
<string name="calibrate_display" msgid="5974642573432039217">"Calibrar pantalla"</string>
@@ -501,10 +500,48 @@
<string name="battery_detail_charging_summary" msgid="1279095653533044008">"Ahorro de batería no está disponible durante la carga"</string>
<string name="battery_detail_switch_title" msgid="6285872470260795421">"Ahorro de batería"</string>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"Reduce el rendimiento y el uso de datos en segundo plano"</string>
+ <string name="keyboard_key_button_template" msgid="6230056639734377300">"Botón <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="keyboard_key_home" msgid="2243500072071305073">"Página principal"</string>
+ <string name="keyboard_key_back" msgid="2337450286042721351">"Atrás"</string>
+ <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"Arriba"</string>
+ <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"Abajo"</string>
+ <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"Izquierda"</string>
+ <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"Derecha"</string>
+ <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"Centro"</string>
+ <string name="keyboard_key_tab" msgid="3871485650463164476">"Tabulación"</string>
+ <string name="keyboard_key_space" msgid="2499861316311153293">"Espacio"</string>
+ <string name="keyboard_key_enter" msgid="5739632123216118137">"Intro"</string>
+ <string name="keyboard_key_backspace" msgid="1559580097512385854">"Retroceso"</string>
+ <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"Reproducir/pausar"</string>
+ <string name="keyboard_key_media_stop" msgid="2859963958595908962">"Detener"</string>
+ <string name="keyboard_key_media_next" msgid="1894394911630345607">"Siguiente"</string>
+ <string name="keyboard_key_media_previous" msgid="4256072387192967261">"Anterior"</string>
+ <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"Retroceder"</string>
+ <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"Avanzar rápido"</string>
+ <string name="keyboard_key_page_up" msgid="5654098530106845603">"Re Pág"</string>
+ <string name="keyboard_key_page_down" msgid="8720502083731906136">"Av Pág"</string>
+ <string name="keyboard_key_forward_del" msgid="1391451334716490176">"Borrar"</string>
+ <string name="keyboard_key_move_home" msgid="2765693292069487486">"Página principal"</string>
+ <string name="keyboard_key_move_end" msgid="5901174332047975247">"Fin"</string>
+ <string name="keyboard_key_insert" msgid="8530501581636082614">"Insertar"</string>
+ <string name="keyboard_key_num_lock" msgid="5052537581246772117">"Bloqueo numérico"</string>
+ <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"Teclado numérico <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"Sistema"</string>
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Pantalla principal"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Recientes"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Atrás"</string>
+ <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Notificaciones"</string>
+ <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"Combinación de teclas"</string>
+ <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"Cambiar método de entrada"</string>
+ <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"Aplicaciones"</string>
+ <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"Asistencia"</string>
+ <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"Navegador"</string>
+ <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"Contactos"</string>
+ <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"Correo electrónico"</string>
+ <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"MI"</string>
+ <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"Música"</string>
+ <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+ <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"Calendario"</string>
<string name="tuner_full_zen_title" msgid="4540823317772234308">"Mostrar con controles de volumen"</string>
<string name="volume_and_do_not_disturb" msgid="3373784330208603030">"No interrumpir"</string>
<string name="volume_dnd_silent" msgid="4363882330723050727">"Combinación de teclas de botones de volumen"</string>
@@ -559,4 +596,14 @@
<string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Mover hacia arriba"</string>
<string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Mover a la izquierda"</string>
<string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Mover a la derecha"</string>
+ <string name="forced_resizable_info_text" msgid="7591061837558867999">"Es posible que la app no se ejecute con la función Multiventana"</string>
+ <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"Posición <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>. Presiona dos veces para editarla."</string>
+ <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. Presiona dos veces para agregarlo."</string>
+ <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"Posición <xliff:g id="POSITION">%1$d</xliff:g>. Presiona dos veces para seleccionarla."</string>
+ <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"Mover <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"Quitar <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"Se agregó <xliff:g id="TILE_NAME">%1$s</xliff:g> a la posición <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+ <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"Se quitó <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"Se movió <xliff:g id="TILE_NAME">%1$s</xliff:g> a la posición <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+ <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Editor de Configuración rápida"</string>
</resources>
diff --git a/packages/SystemUI/res/values-es-rUS/strings_tv.xml b/packages/SystemUI/res/values-es-rUS/strings_tv.xml
index 98ad35b..72ea127 100644
--- a/packages/SystemUI/res/values-es-rUS/strings_tv.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings_tv.xml
@@ -26,6 +26,5 @@
<string name="pip_hold_home" msgid="340086535668778109">"Mantén presionado "<b>"INICIO"</b>" para controlar PIP"</string>
<string name="pip_onboarding_description" msgid="2882896641362814195">"Mantén presionado el botón INICIO para controlar PIP"</string>
<string name="pip_onboarding_button" msgid="3957426748484904611">"Entendido"</string>
- <!-- no translation found for recents_tv_dismiss (3555093879593377731) -->
- <skip />
+ <string name="recents_tv_dismiss" msgid="3555093879593377731">"Descartar"</string>
</resources>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index 5c84999..d8affc9 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -168,6 +168,8 @@
<string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Ignorar <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"Se ha eliminado <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Se han ignorado todas las aplicaciones recientes."</string>
+ <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+ <skip />
<string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Iniciando <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
<string name="accessibility_notification_dismissed" msgid="854211387186306927">"Notificación ignorada"</string>
@@ -236,7 +238,7 @@
<string name="gps_notification_found_text" msgid="4619274244146446464">"Ubicación definida por GPS"</string>
<string name="accessibility_location_active" msgid="2427290146138169014">"Solicitudes de ubicación activas"</string>
<string name="accessibility_clear_all" msgid="5235938559247164925">"Borrar todas las notificaciones"</string>
- <string name="notification_group_overflow_indicator" msgid="1863231301642314183">"+ de <xliff:g id="NUMBER">%s</xliff:g>"</string>
+ <string name="notification_group_overflow_indicator" msgid="1863231301642314183">"<xliff:g id="NUMBER">%s</xliff:g> más"</string>
<string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"Ajustes de notificaciones"</string>
<string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"Ajustes de <xliff:g id="APP_NAME">%s</xliff:g>"</string>
<string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"La pantalla girará automáticamente."</string>
@@ -309,8 +311,7 @@
<string name="recents_search_bar_label" msgid="8074997400187836677">"buscar"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"No se ha podido iniciar <xliff:g id="APP">%s</xliff:g>."</string>
<string name="recents_launch_disabled_message" msgid="1624523193008871793">"La aplicación <xliff:g id="APP">%s</xliff:g> se ha inhabilitado en modo seguro."</string>
- <string name="recents_history_button_label" msgid="5153358867807604821">"Historial"</string>
- <string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Borrar"</string>
+ <string name="recents_stack_action_button_label" msgid="6593727103310426253">"Borrar todo"</string>
<string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"Esta aplicación no admite el modo multiventana."</string>
<string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"La aplicación no admite el modo multiventana"</string>
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"División horizontal"</string>
@@ -499,10 +500,48 @@
<string name="battery_detail_charging_summary" msgid="1279095653533044008">"Ahorro de batería no disponible mientras se carga el dispositivo"</string>
<string name="battery_detail_switch_title" msgid="6285872470260795421">"Ahorro de batería"</string>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"Reduce el rendimiento y las conexiones automáticas"</string>
+ <string name="keyboard_key_button_template" msgid="6230056639734377300">"Botón <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="keyboard_key_home" msgid="2243500072071305073">"Inicio"</string>
+ <string name="keyboard_key_back" msgid="2337450286042721351">"Atrás"</string>
+ <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"Arriba"</string>
+ <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"Abajo"</string>
+ <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"Izquierda"</string>
+ <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"Derecha"</string>
+ <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"Centro"</string>
+ <string name="keyboard_key_tab" msgid="3871485650463164476">"Tabulador"</string>
+ <string name="keyboard_key_space" msgid="2499861316311153293">"Espacio"</string>
+ <string name="keyboard_key_enter" msgid="5739632123216118137">"Intro"</string>
+ <string name="keyboard_key_backspace" msgid="1559580097512385854">"Tecla de retroceso"</string>
+ <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"Reproducir/Pausa"</string>
+ <string name="keyboard_key_media_stop" msgid="2859963958595908962">"Detener"</string>
+ <string name="keyboard_key_media_next" msgid="1894394911630345607">"Siguiente"</string>
+ <string name="keyboard_key_media_previous" msgid="4256072387192967261">"Anterior"</string>
+ <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"Rebobinar"</string>
+ <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"Avance rápido"</string>
+ <string name="keyboard_key_page_up" msgid="5654098530106845603">"Re Pág"</string>
+ <string name="keyboard_key_page_down" msgid="8720502083731906136">"Av Pág"</string>
+ <string name="keyboard_key_forward_del" msgid="1391451334716490176">"Supr"</string>
+ <string name="keyboard_key_move_home" msgid="2765693292069487486">"Inicio"</string>
+ <string name="keyboard_key_move_end" msgid="5901174332047975247">"Fin"</string>
+ <string name="keyboard_key_insert" msgid="8530501581636082614">"Insert"</string>
+ <string name="keyboard_key_num_lock" msgid="5052537581246772117">"Bloq Num"</string>
+ <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"Teclado numérico <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"Sistema"</string>
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Inicio"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Recientes"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Atrás"</string>
+ <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Notificaciones"</string>
+ <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"Combinaciones de teclas"</string>
+ <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"Cambiar método de introducción"</string>
+ <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"Aplicaciones"</string>
+ <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"Asistencia"</string>
+ <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"Navegador"</string>
+ <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"Contactos"</string>
+ <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"Correo electrónico"</string>
+ <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"MI"</string>
+ <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"Música"</string>
+ <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+ <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"Calendario"</string>
<string name="tuner_full_zen_title" msgid="4540823317772234308">"Mostrar con controles de volumen"</string>
<string name="volume_and_do_not_disturb" msgid="3373784330208603030">"No molestar"</string>
<string name="volume_dnd_silent" msgid="4363882330723050727">"Combinación de teclas para los botones de volumen"</string>
@@ -557,4 +596,14 @@
<string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Subir"</string>
<string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Mover a la izquierda"</string>
<string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Mover a la derecha"</string>
+ <string name="forced_resizable_info_text" msgid="7591061837558867999">"Es posible que la aplicación no funcione con el modo multiventana"</string>
+ <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"Posición <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>. Toca dos veces para cambiarla."</string>
+ <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. Toca dos veces para añadirlo."</string>
+ <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"Posición <xliff:g id="POSITION">%1$d</xliff:g>. Toca dos veces para seleccionarla."</string>
+ <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"Mover <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"Quitar <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="TILE_NAME">%1$s</xliff:g> se ha añadido a la posición <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+ <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"<xliff:g id="TILE_NAME">%1$s</xliff:g> se ha quitado"</string>
+ <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="TILE_NAME">%1$s</xliff:g> se ha movido a la posición <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+ <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Editor de ajustes rápidos."</string>
</resources>
diff --git a/packages/SystemUI/res/values-et-rEE/strings.xml b/packages/SystemUI/res/values-et-rEE/strings.xml
index 423166f..f18bf05 100644
--- a/packages/SystemUI/res/values-et-rEE/strings.xml
+++ b/packages/SystemUI/res/values-et-rEE/strings.xml
@@ -168,6 +168,8 @@
<string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Rakendusest <xliff:g id="APP">%s</xliff:g> loobumine."</string>
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"Loobusite rakendusest <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Kõikidest hiljutistest rakendustest on loobutud"</string>
+ <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+ <skip />
<string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Rakenduse <xliff:g id="APP">%s</xliff:g> käivitamine."</string>
<string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g>, <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
<string name="accessibility_notification_dismissed" msgid="854211387186306927">"Märguandest on loobutud."</string>
@@ -309,8 +311,7 @@
<string name="recents_search_bar_label" msgid="8074997400187836677">"otsing"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"Rakendust <xliff:g id="APP">%s</xliff:g> ei saanud käivitada."</string>
<string name="recents_launch_disabled_message" msgid="1624523193008871793">"Rakendus <xliff:g id="APP">%s</xliff:g> on turvarežiimis keelatud."</string>
- <string name="recents_history_button_label" msgid="5153358867807604821">"Ajalugu"</string>
- <string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Kustuta"</string>
+ <string name="recents_stack_action_button_label" msgid="6593727103310426253">"Kustuta kõik"</string>
<string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"See rakendus ei toeta mitut akent"</string>
<string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"Rakendus ei toeta mitut akent"</string>
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Horisontaalne poolitamine"</string>
@@ -499,10 +500,48 @@
<string name="battery_detail_charging_summary" msgid="1279095653533044008">"Akusäästja pole laadimise ajal saadaval"</string>
<string name="battery_detail_switch_title" msgid="6285872470260795421">"Akusäästja"</string>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"Vähendab jõudlust ja taustaandmeid"</string>
+ <string name="keyboard_key_button_template" msgid="6230056639734377300">"Nupp <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="keyboard_key_home" msgid="2243500072071305073">"Avaekraan"</string>
+ <string name="keyboard_key_back" msgid="2337450286042721351">"Tagasi"</string>
+ <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"Üles"</string>
+ <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"Alla"</string>
+ <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"Vasakule"</string>
+ <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"Paremale"</string>
+ <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"Keskele"</string>
+ <string name="keyboard_key_tab" msgid="3871485650463164476">"Tabulaator"</string>
+ <string name="keyboard_key_space" msgid="2499861316311153293">"Tühik"</string>
+ <string name="keyboard_key_enter" msgid="5739632123216118137">"Sisestusklahv"</string>
+ <string name="keyboard_key_backspace" msgid="1559580097512385854">"Tagasilüke"</string>
+ <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"Esita/peata"</string>
+ <string name="keyboard_key_media_stop" msgid="2859963958595908962">"Peata"</string>
+ <string name="keyboard_key_media_next" msgid="1894394911630345607">"Järgmine"</string>
+ <string name="keyboard_key_media_previous" msgid="4256072387192967261">"Eelmine"</string>
+ <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"Keri tagasi"</string>
+ <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"Keri edasi"</string>
+ <string name="keyboard_key_page_up" msgid="5654098530106845603">"Lehe võrra üles"</string>
+ <string name="keyboard_key_page_down" msgid="8720502083731906136">"Lehe võrra alla"</string>
+ <string name="keyboard_key_forward_del" msgid="1391451334716490176">"Kustuta"</string>
+ <string name="keyboard_key_move_home" msgid="2765693292069487486">"Avaekraan"</string>
+ <string name="keyboard_key_move_end" msgid="5901174332047975247">"Lõpp"</string>
+ <string name="keyboard_key_insert" msgid="8530501581636082614">"Sisesta"</string>
+ <string name="keyboard_key_num_lock" msgid="5052537581246772117">"Numbrilukk"</string>
+ <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"Numbriklahvistik <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"Süsteem"</string>
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Avaekraan"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Hiljutised"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Tagasi"</string>
+ <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Märguanded"</string>
+ <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"Klaviatuuri otseteed"</string>
+ <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"Sisestusmeetodi vahetamine"</string>
+ <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"Rakendused"</string>
+ <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"Abi"</string>
+ <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"Brauser"</string>
+ <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"Kontaktid"</string>
+ <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"E-post"</string>
+ <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"IM (kiirsuhtlus)"</string>
+ <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"Muusika"</string>
+ <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+ <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"Kalender"</string>
<string name="tuner_full_zen_title" msgid="4540823317772234308">"Kuva koos helitugevuse juhtnuppudega"</string>
<string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Mitte segada"</string>
<string name="volume_dnd_silent" msgid="4363882330723050727">"Helitugevuse nuppude otsetee"</string>
@@ -557,4 +596,14 @@
<string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Liigu üles"</string>
<string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Liigu vasakule"</string>
<string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Liigu paremale"</string>
+ <string name="forced_resizable_info_text" msgid="7591061837558867999">"Rakendus ei pruugi mitme akna režiimis töötada"</string>
+ <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"Asend <xliff:g id="POSITION">%1$d</xliff:g>, paan <xliff:g id="TILE_NAME">%2$s</xliff:g>. Topeltpuudutage muutmiseks."</string>
+ <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. Topeltpuudutage lisamiseks."</string>
+ <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"Asend <xliff:g id="POSITION">%1$d</xliff:g>. Topeltpuudutage valimiseks."</string>
+ <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"Paani <xliff:g id="TILE_NAME">%1$s</xliff:g> teisaldamine"</string>
+ <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"Paani <xliff:g id="TILE_NAME">%1$s</xliff:g> eemaldamine"</string>
+ <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"Paan <xliff:g id="TILE_NAME">%1$s</xliff:g> lisati asendisse <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+ <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"Paan <xliff:g id="TILE_NAME">%1$s</xliff:g> eemaldati"</string>
+ <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"Paan <xliff:g id="TILE_NAME">%1$s</xliff:g> teisaldati asendisse <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+ <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Kiirseadete redigeerija."</string>
</resources>
diff --git a/packages/SystemUI/res/values-eu-rES/strings.xml b/packages/SystemUI/res/values-eu-rES/strings.xml
index 435e821..575f8749 100644
--- a/packages/SystemUI/res/values-eu-rES/strings.xml
+++ b/packages/SystemUI/res/values-eu-rES/strings.xml
@@ -168,6 +168,8 @@
<string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Baztertu <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> baztertu da."</string>
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Azken aplikazio guztiak baztertu da."</string>
+ <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+ <skip />
<string name="accessibility_recents_item_launched" msgid="7616039892382525203">"<xliff:g id="APP">%s</xliff:g> hasten."</string>
<string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
<string name="accessibility_notification_dismissed" msgid="854211387186306927">"Jakinarazpena baztertu da."</string>
@@ -236,8 +238,7 @@
<string name="gps_notification_found_text" msgid="4619274244146446464">"Kokapena GPS bidez ezarri da"</string>
<string name="accessibility_location_active" msgid="2427290146138169014">"Aplikazioen kokapen-eskaerak aktibo daude"</string>
<string name="accessibility_clear_all" msgid="5235938559247164925">"Garbitu jakinarazpen guztiak."</string>
- <!-- no translation found for notification_group_overflow_indicator (1863231301642314183) -->
- <skip />
+ <string name="notification_group_overflow_indicator" msgid="1863231301642314183">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string>
<string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"Jakinarazpen-ezarpenak"</string>
<string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"<xliff:g id="APP_NAME">%s</xliff:g> ezarpenak"</string>
<string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Pantaila automatikoki biratuko da."</string>
@@ -310,8 +311,7 @@
<string name="recents_search_bar_label" msgid="8074997400187836677">"bilatu"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"Ezin izan da hasi <xliff:g id="APP">%s</xliff:g>."</string>
<string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g> desgaituta dago modu seguruan."</string>
- <string name="recents_history_button_label" msgid="5153358867807604821">"Historia"</string>
- <string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Garbitu"</string>
+ <string name="recents_stack_action_button_label" msgid="6593727103310426253">"Garbitu guztiak"</string>
<string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"Aplikazioak ez du onartzen leiho bat baino gehiago erabiltzea"</string>
<string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"Aplikazioak ez du onartzen leiho bat baino gehiago erabiltzea"</string>
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Zatitze horizontala"</string>
@@ -480,8 +480,7 @@
<string name="notification_importance_max" msgid="5806278962376556491">"Erakutsi jakinarazpen hauek zerrendaren goialdean, agerrarazi pantailan eta egin soinua"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Ezarpen gehiago"</string>
<string name="notification_done" msgid="5279426047273930175">"Eginda"</string>
- <!-- no translation found for notification_gear_accessibility (94429150213089611) -->
- <skip />
+ <string name="notification_gear_accessibility" msgid="94429150213089611">"<xliff:g id="APP_NAME">%1$s</xliff:g> aplikazioaren jakinarazpenak kontrolatzeko aukerak"</string>
<string name="color_and_appearance" msgid="1254323855964993144">"Kolorea eta itxura"</string>
<string name="night_mode" msgid="3540405868248625488">"Gau modua"</string>
<string name="calibrate_display" msgid="5974642573432039217">"Kalibratu pantaila"</string>
@@ -501,10 +500,48 @@
<string name="battery_detail_charging_summary" msgid="1279095653533044008">"Bateria-aurrezlea ez dago erabilgarri gailua kargatzen ari denean"</string>
<string name="battery_detail_switch_title" msgid="6285872470260795421">"Bateria-aurrezlea"</string>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"Errendimendua eta atzeko planoko datuen erabilera murrizten ditu"</string>
+ <string name="keyboard_key_button_template" msgid="6230056639734377300">"<xliff:g id="NAME">%1$s</xliff:g> botoia"</string>
+ <string name="keyboard_key_home" msgid="2243500072071305073">"Hasiera"</string>
+ <string name="keyboard_key_back" msgid="2337450286042721351">"Atzera"</string>
+ <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"Gora"</string>
+ <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"Behera"</string>
+ <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"Ezkerrera"</string>
+ <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"Eskuinera"</string>
+ <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"Erdiratu"</string>
+ <string name="keyboard_key_tab" msgid="3871485650463164476">"Tabuladorea"</string>
+ <string name="keyboard_key_space" msgid="2499861316311153293">"Zuriunea"</string>
+ <string name="keyboard_key_enter" msgid="5739632123216118137">"Sartu"</string>
+ <string name="keyboard_key_backspace" msgid="1559580097512385854">"Atzera"</string>
+ <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"Erreproduzitu/Pausatu"</string>
+ <string name="keyboard_key_media_stop" msgid="2859963958595908962">"Gelditu"</string>
+ <string name="keyboard_key_media_next" msgid="1894394911630345607">"Hurrengoa"</string>
+ <string name="keyboard_key_media_previous" msgid="4256072387192967261">"Aurrekoa"</string>
+ <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"Atzeratu"</string>
+ <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"Aurreratu"</string>
+ <string name="keyboard_key_page_up" msgid="5654098530106845603">"Orria gora"</string>
+ <string name="keyboard_key_page_down" msgid="8720502083731906136">"Orria behera"</string>
+ <string name="keyboard_key_forward_del" msgid="1391451334716490176">"Ezabatu"</string>
+ <string name="keyboard_key_move_home" msgid="2765693292069487486">"Hasiera"</string>
+ <string name="keyboard_key_move_end" msgid="5901174332047975247">"Amaitu"</string>
+ <string name="keyboard_key_insert" msgid="8530501581636082614">"Txertatu"</string>
+ <string name="keyboard_key_num_lock" msgid="5052537581246772117">"Blok Zenb"</string>
+ <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"Zenbaki-teklatuko <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"Sistema"</string>
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Hasierako pantaila"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Azkenak"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Atzera"</string>
+ <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Jakinarazpenak"</string>
+ <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"Lasterbideak"</string>
+ <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"Aldatu idazketa-metodoa"</string>
+ <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"Aplikazioak"</string>
+ <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"Laguntzailea"</string>
+ <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"Arakatzailea"</string>
+ <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"Kontaktuak"</string>
+ <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"Helbide elektronikoa"</string>
+ <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"Istanteko mezularitza"</string>
+ <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"Musika"</string>
+ <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+ <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"Egutegia"</string>
<string name="tuner_full_zen_title" msgid="4540823317772234308">"Erakutsi bolumena kontrolatzeko aukerekin"</string>
<string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Ez molestatu"</string>
<string name="volume_dnd_silent" msgid="4363882330723050727">"Bolumen-botoietarako lasterbidea"</string>
@@ -559,4 +596,14 @@
<string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Eraman gora"</string>
<string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Eraman ezkerrera"</string>
<string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Eraman eskuinera"</string>
+ <string name="forced_resizable_info_text" msgid="7591061837558867999">"Baliteke aplikazioak ez funtzionatzea leiho anitzetan."</string>
+ <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"<xliff:g id="POSITION">%1$d</xliff:g>. posizioa, <xliff:g id="TILE_NAME">%2$s</xliff:g>. Editatzeko, sakatu birritan."</string>
+ <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. Gehitzeko, sakatu birritan."</string>
+ <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"<xliff:g id="POSITION">%1$d</xliff:g>. posizioa. Hautatzeko, sakatu birritan."</string>
+ <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"Mugitu <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"Kendu <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="TILE_NAME">%1$s</xliff:g> gehitu da <xliff:g id="POSITION">%2$d</xliff:g>. posizioan"</string>
+ <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"Kendu da <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="TILE_NAME">%1$s</xliff:g> <xliff:g id="POSITION">%2$d</xliff:g>. posiziora eraman da"</string>
+ <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Ezarpen bizkorren editorea."</string>
</resources>
diff --git a/packages/SystemUI/res/values-eu-rES/strings_tv.xml b/packages/SystemUI/res/values-eu-rES/strings_tv.xml
index f28ec5e..b812143 100644
--- a/packages/SystemUI/res/values-eu-rES/strings_tv.xml
+++ b/packages/SystemUI/res/values-eu-rES/strings_tv.xml
@@ -26,6 +26,5 @@
<string name="pip_hold_home" msgid="340086535668778109"><b>"HASIERA"</b>" PIP kontrolatzeko"</string>
<string name="pip_onboarding_description" msgid="2882896641362814195">"Eduki sakatuta hasierako botoia pantaila txikia kontrolatzeko"</string>
<string name="pip_onboarding_button" msgid="3957426748484904611">"Ados"</string>
- <!-- no translation found for recents_tv_dismiss (3555093879593377731) -->
- <skip />
+ <string name="recents_tv_dismiss" msgid="3555093879593377731">"Baztertu"</string>
</resources>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index f2e977c..7c2da10 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -168,6 +168,8 @@
<string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"رد کردن <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> نادیده گرفته شد."</string>
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"همه برنامههای اخیر رد شدند."</string>
+ <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+ <skip />
<string name="accessibility_recents_item_launched" msgid="7616039892382525203">"<xliff:g id="APP">%s</xliff:g> در حال شروع به کار است."</string>
<string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
<string name="accessibility_notification_dismissed" msgid="854211387186306927">"اعلان ردشد."</string>
@@ -236,8 +238,7 @@
<string name="gps_notification_found_text" msgid="4619274244146446464">"مکان تنظیم شده توسط GPS"</string>
<string name="accessibility_location_active" msgid="2427290146138169014">"درخواستهای موقعیت مکانی فعال است"</string>
<string name="accessibility_clear_all" msgid="5235938559247164925">"پاک کردن تمام اعلانها"</string>
- <!-- no translation found for notification_group_overflow_indicator (1863231301642314183) -->
- <skip />
+ <string name="notification_group_overflow_indicator" msgid="1863231301642314183">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string>
<string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"تنظیمات اعلان"</string>
<string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"تنظیمات <xliff:g id="APP_NAME">%s</xliff:g>"</string>
<string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"صفحه به صورت خودکار میچرخد."</string>
@@ -310,8 +311,7 @@
<string name="recents_search_bar_label" msgid="8074997400187836677">"جستجو"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g> شروع نشد."</string>
<string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g> در حالت ایمن غیرفعال است."</string>
- <string name="recents_history_button_label" msgid="5153358867807604821">"سابقه"</string>
- <string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"پاک کردن"</string>
+ <string name="recents_stack_action_button_label" msgid="6593727103310426253">"پاک کردن همه"</string>
<string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"این برنامه از چندپنجره پشتیبانی نمیکند"</string>
<string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"برنامه از چندپنجره پشتیبانی نمیکند"</string>
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"تقسیم افقی"</string>
@@ -480,8 +480,7 @@
<string name="notification_importance_max" msgid="5806278962376556491">"در بالای فهرست اعلان نشان داده شوند، در صفحه نشان داده شوند و صدادار باشند"</string>
<string name="notification_more_settings" msgid="816306283396553571">"تنظیمات بیشتر"</string>
<string name="notification_done" msgid="5279426047273930175">"تمام"</string>
- <!-- no translation found for notification_gear_accessibility (94429150213089611) -->
- <skip />
+ <string name="notification_gear_accessibility" msgid="94429150213089611">"کنترلهای اعلان <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="color_and_appearance" msgid="1254323855964993144">"رنگ و ظاهر"</string>
<string name="night_mode" msgid="3540405868248625488">"حالت شب"</string>
<string name="calibrate_display" msgid="5974642573432039217">"درجهبندی نمایشگر"</string>
@@ -501,10 +500,48 @@
<string name="battery_detail_charging_summary" msgid="1279095653533044008">"هنگام شارژ شدن، «بهینهسازی باتری» در دسترس نیست"</string>
<string name="battery_detail_switch_title" msgid="6285872470260795421">"بهینهسازی باتری"</string>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"عملکرد و اطلاعات پسزمینه را کاهش میدهد"</string>
+ <string name="keyboard_key_button_template" msgid="6230056639734377300">"دکمه <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="keyboard_key_home" msgid="2243500072071305073">"ابتدا"</string>
+ <string name="keyboard_key_back" msgid="2337450286042721351">"برگشت"</string>
+ <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"بالا"</string>
+ <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"پایین"</string>
+ <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"چپ"</string>
+ <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"راست"</string>
+ <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"مرکز"</string>
+ <string name="keyboard_key_tab" msgid="3871485650463164476">"جهش"</string>
+ <string name="keyboard_key_space" msgid="2499861316311153293">"فاصله"</string>
+ <string name="keyboard_key_enter" msgid="5739632123216118137">"ورود"</string>
+ <string name="keyboard_key_backspace" msgid="1559580097512385854">"پسبر"</string>
+ <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"پخش/مکث"</string>
+ <string name="keyboard_key_media_stop" msgid="2859963958595908962">"توقف"</string>
+ <string name="keyboard_key_media_next" msgid="1894394911630345607">"بعدی"</string>
+ <string name="keyboard_key_media_previous" msgid="4256072387192967261">"قبلی"</string>
+ <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"عقب بردن"</string>
+ <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"جلو بردن سریع"</string>
+ <string name="keyboard_key_page_up" msgid="5654098530106845603">"صفحه بعدی"</string>
+ <string name="keyboard_key_page_down" msgid="8720502083731906136">"صفحه قبلی"</string>
+ <string name="keyboard_key_forward_del" msgid="1391451334716490176">"حذف"</string>
+ <string name="keyboard_key_move_home" msgid="2765693292069487486">"ابتدا"</string>
+ <string name="keyboard_key_move_end" msgid="5901174332047975247">"انتها"</string>
+ <string name="keyboard_key_insert" msgid="8530501581636082614">"درج"</string>
+ <string name="keyboard_key_num_lock" msgid="5052537581246772117">"قفل اعداد"</string>
+ <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"صفحهکلید عددی <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"سیستم"</string>
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"صفحه اصلی"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"موارد اخیر"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"برگشت"</string>
+ <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"اعلانها"</string>
+ <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"میانبرهای صفحهکلید"</string>
+ <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"تغییر روش ورودی"</string>
+ <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"برنامهها"</string>
+ <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"همیار"</string>
+ <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"مرورگر"</string>
+ <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"مخاطبین"</string>
+ <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"رایانامه"</string>
+ <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"پیام فوری"</string>
+ <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"موسیقی"</string>
+ <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+ <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"تقویم"</string>
<string name="tuner_full_zen_title" msgid="4540823317772234308">"نمایش با کنترلهای صدا"</string>
<string name="volume_and_do_not_disturb" msgid="3373784330208603030">"مزاحم نشوید"</string>
<string name="volume_dnd_silent" msgid="4363882330723050727">"میانبر دکمههای صدا"</string>
@@ -540,8 +577,7 @@
<string name="select_keycode" msgid="7413765103381924584">"کلید صفحهکلید را انتخاب کنید"</string>
<string name="preview" msgid="9077832302472282938">"پیشنمایش"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"کشیدن برای افزودن کاشیها"</string>
- <!-- no translation found for drag_to_remove_tiles (3361212377437088062) -->
- <skip />
+ <string name="drag_to_remove_tiles" msgid="3361212377437088062">"برای حذف، به اینجا بکشید"</string>
<string name="qs_edit" msgid="2232596095725105230">"ویرایش"</string>
<string name="tuner_time" msgid="6572217313285536011">"زمان"</string>
<string-array name="clock_options">
@@ -560,4 +596,14 @@
<string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"انتقال به بالا"</string>
<string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"انتقال به چپ"</string>
<string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"انتقال به راست"</string>
+ <string name="forced_resizable_info_text" msgid="7591061837558867999">"برنامه ممکن است با چندپنجره کار نکند"</string>
+ <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"موقعیت <xliff:g id="POSITION">%1$d</xliff:g>، <xliff:g id="TILE_NAME">%2$s</xliff:g>. برای ویرایش دو ضربه سریع بزنید."</string>
+ <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. برای افزودن دو ضربه سریع بزنید."</string>
+ <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"موقعیت <xliff:g id="POSITION">%1$d</xliff:g>. برای انتخاب دو ضربه سریع بزنید."</string>
+ <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"انتقال <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"حذف <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="TILE_NAME">%1$s</xliff:g> به موقعیت <xliff:g id="POSITION">%2$d</xliff:g> اضافه میشود"</string>
+ <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"<xliff:g id="TILE_NAME">%1$s</xliff:g> حذف میشود"</string>
+ <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="TILE_NAME">%1$s</xliff:g> به موقعیت <xliff:g id="POSITION">%2$d</xliff:g> منتقل شد"</string>
+ <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"ویرایشگر تنظیمات سریع."</string>
</resources>
diff --git a/packages/SystemUI/res/values-fa/strings_tv.xml b/packages/SystemUI/res/values-fa/strings_tv.xml
index 5177724..0d028d8 100644
--- a/packages/SystemUI/res/values-fa/strings_tv.xml
+++ b/packages/SystemUI/res/values-fa/strings_tv.xml
@@ -26,6 +26,5 @@
<string name="pip_hold_home" msgid="340086535668778109">"کنترل PIP با نگهداشتن "<b>"HOME"</b></string>
<string name="pip_onboarding_description" msgid="2882896641362814195">"برای کنترل PIP دکمه صفحه اصلی را فشار داده و نگهدارید"</string>
<string name="pip_onboarding_button" msgid="3957426748484904611">"متوجه شدم"</string>
- <!-- no translation found for recents_tv_dismiss (3555093879593377731) -->
- <skip />
+ <string name="recents_tv_dismiss" msgid="3555093879593377731">"رد کردن"</string>
</resources>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index 11cb91e..6db0a3e 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -168,6 +168,8 @@
<string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Hylätään <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> hylättiin."</string>
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Kaikki viimeisimmät sovellukset on hylätty."</string>
+ <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+ <skip />
<string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Käynnistetään <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
<string name="accessibility_notification_dismissed" msgid="854211387186306927">"Ilmoitus hylätty."</string>
@@ -236,8 +238,7 @@
<string name="gps_notification_found_text" msgid="4619274244146446464">"Sijainti määritetty GPS:n avulla"</string>
<string name="accessibility_location_active" msgid="2427290146138169014">"Sijaintipyynnöt aktiiviset"</string>
<string name="accessibility_clear_all" msgid="5235938559247164925">"Tyhjennä kaikki ilmoitukset."</string>
- <!-- no translation found for notification_group_overflow_indicator (1863231301642314183) -->
- <skip />
+ <string name="notification_group_overflow_indicator" msgid="1863231301642314183">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string>
<string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"Ilmoitusasetukset"</string>
<string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"Asetukset – <xliff:g id="APP_NAME">%s</xliff:g>"</string>
<string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Ruutu kääntyy automaattisesti."</string>
@@ -310,8 +311,7 @@
<string name="recents_search_bar_label" msgid="8074997400187836677">"haku"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"Sovelluksen <xliff:g id="APP">%s</xliff:g> käynnistäminen epäonnistui."</string>
<string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g> on poistettu käytöstä vikasietotilassa."</string>
- <string name="recents_history_button_label" msgid="5153358867807604821">"Historia"</string>
- <string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Tyhjennä"</string>
+ <string name="recents_stack_action_button_label" msgid="6593727103310426253">"Tyhjennä kaikki"</string>
<string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"Tämä sovellus ei tue usean ikkunan tilaa."</string>
<string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"Sovellus ei tue usean ikkunan tilaa."</string>
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Vaakasuuntainen jako"</string>
@@ -480,8 +480,7 @@
<string name="notification_importance_max" msgid="5806278962376556491">"Näytä ilmoitukset näytöllä ja ilmoitusluettelon yläosassa ja salli niiden äänet."</string>
<string name="notification_more_settings" msgid="816306283396553571">"Lisäasetukset"</string>
<string name="notification_done" msgid="5279426047273930175">"Valmis"</string>
- <!-- no translation found for notification_gear_accessibility (94429150213089611) -->
- <skip />
+ <string name="notification_gear_accessibility" msgid="94429150213089611">"<xliff:g id="APP_NAME">%1$s</xliff:g>-ilmoitusten hallinta"</string>
<string name="color_and_appearance" msgid="1254323855964993144">"Väri ja ulkoasu"</string>
<string name="night_mode" msgid="3540405868248625488">"Yötila"</string>
<string name="calibrate_display" msgid="5974642573432039217">"Kalibroi näyttö"</string>
@@ -501,10 +500,48 @@
<string name="battery_detail_charging_summary" msgid="1279095653533044008">"Virransäästö ei ole käytettävissä latauksen aikana."</string>
<string name="battery_detail_switch_title" msgid="6285872470260795421">"Virransäästö"</string>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"Rajoittaa suorituskykyä ja taustatiedonsiirtoa."</string>
+ <string name="keyboard_key_button_template" msgid="6230056639734377300">"Painike <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="keyboard_key_home" msgid="2243500072071305073">"Home"</string>
+ <string name="keyboard_key_back" msgid="2337450286042721351">"Takaisin"</string>
+ <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"Ylös"</string>
+ <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"Alas"</string>
+ <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"Vasemmalle"</string>
+ <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"Oikealle"</string>
+ <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"Keskelle"</string>
+ <string name="keyboard_key_tab" msgid="3871485650463164476">"Sarkain"</string>
+ <string name="keyboard_key_space" msgid="2499861316311153293">"Välilyönti"</string>
+ <string name="keyboard_key_enter" msgid="5739632123216118137">"Enter"</string>
+ <string name="keyboard_key_backspace" msgid="1559580097512385854">"Askelpalautin"</string>
+ <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"Toisto/keskeytys"</string>
+ <string name="keyboard_key_media_stop" msgid="2859963958595908962">"Pysäytä"</string>
+ <string name="keyboard_key_media_next" msgid="1894394911630345607">"Seuraava"</string>
+ <string name="keyboard_key_media_previous" msgid="4256072387192967261">"Edellinen"</string>
+ <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"Kelaa taaksepäin"</string>
+ <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"Kelaa eteenpäin"</string>
+ <string name="keyboard_key_page_up" msgid="5654098530106845603">"Page Up"</string>
+ <string name="keyboard_key_page_down" msgid="8720502083731906136">"Page Down"</string>
+ <string name="keyboard_key_forward_del" msgid="1391451334716490176">"Delete"</string>
+ <string name="keyboard_key_move_home" msgid="2765693292069487486">"Home"</string>
+ <string name="keyboard_key_move_end" msgid="5901174332047975247">"End"</string>
+ <string name="keyboard_key_insert" msgid="8530501581636082614">"Insert"</string>
+ <string name="keyboard_key_num_lock" msgid="5052537581246772117">"Num Lock"</string>
+ <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"Numeronäppäimistö <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"Järjestelmä"</string>
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Aloitusnäyttö"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Viimeaikaiset"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Takaisin"</string>
+ <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Ilmoitukset"</string>
+ <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"Pikanäppäimet"</string>
+ <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"Vaihda syöttötapaa"</string>
+ <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"Sovellukset"</string>
+ <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"Apusovellus"</string>
+ <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"Selain"</string>
+ <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"Yhteystiedot"</string>
+ <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"Sähköposti"</string>
+ <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"Pikaviesti"</string>
+ <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"Musiikki"</string>
+ <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+ <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"Kalenteri"</string>
<string name="tuner_full_zen_title" msgid="4540823317772234308">"Näytä äänenvoimakkuuden säätimien yhteydessä"</string>
<string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Älä häiritse"</string>
<string name="volume_dnd_silent" msgid="4363882330723050727">"Äänenvoimakkuuspainikkeiden pikanäppäin"</string>
@@ -559,4 +596,14 @@
<string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Siirrä ylöspäin"</string>
<string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Siirrä vasemmalle"</string>
<string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Siirrä oikealle"</string>
+ <string name="forced_resizable_info_text" msgid="7591061837558867999">"Sovellus ei ehkä toimi usean ikkunan tilassa."</string>
+ <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"Paikka <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>. Muokkaa kaksoisnapauttamalla."</string>
+ <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. Lisää kaksoisnapauttamalla."</string>
+ <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"Paikka <xliff:g id="POSITION">%1$d</xliff:g>. Valitse kaksoisnapauttamalla."</string>
+ <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"Siirrä <xliff:g id="TILE_NAME">%1$s</xliff:g>."</string>
+ <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"Poista <xliff:g id="TILE_NAME">%1$s</xliff:g>."</string>
+ <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="TILE_NAME">%1$s</xliff:g> lisättiin paikkaan <xliff:g id="POSITION">%2$d</xliff:g>."</string>
+ <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"<xliff:g id="TILE_NAME">%1$s</xliff:g> poistettiin."</string>
+ <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="TILE_NAME">%1$s</xliff:g> siirrettiin paikkaan <xliff:g id="POSITION">%2$d</xliff:g>."</string>
+ <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Pika-asetusten muokkausnäkymä"</string>
</resources>
diff --git a/packages/SystemUI/res/values-fi/strings_tv.xml b/packages/SystemUI/res/values-fi/strings_tv.xml
index 642ed20..9124f67 100644
--- a/packages/SystemUI/res/values-fi/strings_tv.xml
+++ b/packages/SystemUI/res/values-fi/strings_tv.xml
@@ -26,6 +26,5 @@
<string name="pip_hold_home" msgid="340086535668778109">"PIP: paina pitkään "<b>"aloituspain"</b>"."</string>
<string name="pip_onboarding_description" msgid="2882896641362814195">"Hallinnoi PIP-tilaa painamalla ALOITUSNÄYTTÖ-painiketta pitkään."</string>
<string name="pip_onboarding_button" msgid="3957426748484904611">"Selvä"</string>
- <!-- no translation found for recents_tv_dismiss (3555093879593377731) -->
- <skip />
+ <string name="recents_tv_dismiss" msgid="3555093879593377731">"Hylkää"</string>
</resources>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index c647cc9..89c6826 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -168,6 +168,8 @@
<string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Supprimer <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"Application \"<xliff:g id="APP">%s</xliff:g>\" ignorée."</string>
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Toutes les applications récentes ont été supprimées."</string>
+ <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+ <skip />
<string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Lancement de <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
<string name="accessibility_notification_dismissed" msgid="854211387186306927">"Notification masquée"</string>
@@ -236,8 +238,7 @@
<string name="gps_notification_found_text" msgid="4619274244146446464">"Position définie par GPS"</string>
<string name="accessibility_location_active" msgid="2427290146138169014">"Demandes de localisation actives"</string>
<string name="accessibility_clear_all" msgid="5235938559247164925">"Supprimer toutes les notifications"</string>
- <!-- no translation found for notification_group_overflow_indicator (1863231301642314183) -->
- <skip />
+ <string name="notification_group_overflow_indicator" msgid="1863231301642314183">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string>
<string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"Paramètres de notification"</string>
<string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"Paramètres de <xliff:g id="APP_NAME">%s</xliff:g>"</string>
<string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"L\'écran pivote automatiquement."</string>
@@ -310,8 +311,7 @@
<string name="recents_search_bar_label" msgid="8074997400187836677">"rechercher"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"Impossible de lancer <xliff:g id="APP">%s</xliff:g>."</string>
<string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g> est désactivée en mode sécurisé."</string>
- <string name="recents_history_button_label" msgid="5153358867807604821">"Historique"</string>
- <string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Effacer"</string>
+ <string name="recents_stack_action_button_label" msgid="6593727103310426253">"Effacer tout"</string>
<string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"Cette application ne prend pas en charge le mode multifenêtre"</string>
<string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"L\'application ne prend pas en charge le mode multifenêtre"</string>
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Séparation horizontale"</string>
@@ -480,8 +480,7 @@
<string name="notification_importance_max" msgid="5806278962376556491">"Afficher en haut de la liste des notifications, afficher sur l\'écran et émettre un son"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Plus de paramètres"</string>
<string name="notification_done" msgid="5279426047273930175">"Terminé"</string>
- <!-- no translation found for notification_gear_accessibility (94429150213089611) -->
- <skip />
+ <string name="notification_gear_accessibility" msgid="94429150213089611">"Commandes de notification pour <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="color_and_appearance" msgid="1254323855964993144">"Couleur et apparence"</string>
<string name="night_mode" msgid="3540405868248625488">"Mode Nuit"</string>
<string name="calibrate_display" msgid="5974642573432039217">"Calibrer l\'affichage"</string>
@@ -501,10 +500,48 @@
<string name="battery_detail_charging_summary" msgid="1279095653533044008">"Le mode Économie d\'énergie n\'est pas accessible pendant la charge"</string>
<string name="battery_detail_switch_title" msgid="6285872470260795421">"Économie d\'énergie"</string>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"Réduit les performances et les données en arrière-plan"</string>
+ <string name="keyboard_key_button_template" msgid="6230056639734377300">"Bouton <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="keyboard_key_home" msgid="2243500072071305073">"Accueil"</string>
+ <string name="keyboard_key_back" msgid="2337450286042721351">"Précédent"</string>
+ <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"Haut"</string>
+ <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"Bas"</string>
+ <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"Gauche"</string>
+ <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"Droite"</string>
+ <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"Centrer"</string>
+ <string name="keyboard_key_tab" msgid="3871485650463164476">"Tabulation"</string>
+ <string name="keyboard_key_space" msgid="2499861316311153293">"Espace"</string>
+ <string name="keyboard_key_enter" msgid="5739632123216118137">"Entrée"</string>
+ <string name="keyboard_key_backspace" msgid="1559580097512385854">"Retour arrière"</string>
+ <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"Lecture/Pause"</string>
+ <string name="keyboard_key_media_stop" msgid="2859963958595908962">"Arrêter"</string>
+ <string name="keyboard_key_media_next" msgid="1894394911630345607">"Suivant"</string>
+ <string name="keyboard_key_media_previous" msgid="4256072387192967261">"Précédent"</string>
+ <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"Reculer"</string>
+ <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"Avance rapide"</string>
+ <string name="keyboard_key_page_up" msgid="5654098530106845603">"Page précédente"</string>
+ <string name="keyboard_key_page_down" msgid="8720502083731906136">"Page suivante"</string>
+ <string name="keyboard_key_forward_del" msgid="1391451334716490176">"Supprimer"</string>
+ <string name="keyboard_key_move_home" msgid="2765693292069487486">"Accueil"</string>
+ <string name="keyboard_key_move_end" msgid="5901174332047975247">"Fin"</string>
+ <string name="keyboard_key_insert" msgid="8530501581636082614">"Insérer"</string>
+ <string name="keyboard_key_num_lock" msgid="5052537581246772117">"Verr num"</string>
+ <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"Pavé numérique <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"Système"</string>
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Accueil"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Récents"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Précédent"</string>
+ <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Notifications"</string>
+ <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"Raccourcis clavier"</string>
+ <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"Changer de méthode d\'entrée"</string>
+ <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"Applications"</string>
+ <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"Assistance"</string>
+ <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"Navigateur"</string>
+ <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"Contacts"</string>
+ <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"Courriel"</string>
+ <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"MI"</string>
+ <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"Musique"</string>
+ <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+ <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"Agenda"</string>
<string name="tuner_full_zen_title" msgid="4540823317772234308">"Afficher avec les commandes de volume"</string>
<string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Ne pas déranger"</string>
<string name="volume_dnd_silent" msgid="4363882330723050727">"Raccourci des boutons de volume"</string>
@@ -559,4 +596,14 @@
<string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Déplacer vers le haut"</string>
<string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Déplacer vers la gauche"</string>
<string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Déplacer vers la droite"</string>
+ <string name="forced_resizable_info_text" msgid="7591061837558867999">"Il est possible que l\'application ne fonctionne pas en mode Multi-fenêtre."</string>
+ <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"Position <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>. Touchez deux fois pour modifier."</string>
+ <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. Touchez deux fois pour ajouter."</string>
+ <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"Position : <xliff:g id="POSITION">%1$d</xliff:g>. Touchez deux fois pour sélectionner."</string>
+ <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"Déplacer <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"Supprimer <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="TILE_NAME">%1$s</xliff:g> a été ajouté à la position <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+ <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"<xliff:g id="TILE_NAME">%1$s</xliff:g> a été supprimé"</string>
+ <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="TILE_NAME">%1$s</xliff:g> a été déplacé à la position <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+ <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Éditeur de paramètres rapides."</string>
</resources>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings_tv.xml b/packages/SystemUI/res/values-fr-rCA/strings_tv.xml
index 1ae3c5c..597a588 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings_tv.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings_tv.xml
@@ -26,6 +26,5 @@
<string name="pip_hold_home" msgid="340086535668778109">"Maint. enf. "<b>"ACC."</b>" pr gér. mode IDI"</string>
<string name="pip_onboarding_description" msgid="2882896641362814195">"Maintenez enfoncé le bouton ACCUEIL pour gérer le mode IDI."</string>
<string name="pip_onboarding_button" msgid="3957426748484904611">"OK"</string>
- <!-- no translation found for recents_tv_dismiss (3555093879593377731) -->
- <skip />
+ <string name="recents_tv_dismiss" msgid="3555093879593377731">"Fermer"</string>
</resources>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index 7d91f6f..2f99b94 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -168,6 +168,8 @@
<string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Supprimer <xliff:g id="APP">%s</xliff:g>"</string>
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"Application \"<xliff:g id="APP">%s</xliff:g>\" ignorée."</string>
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Toutes les applications récentes ont été supprimées."</string>
+ <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+ <skip />
<string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Lancement de <xliff:g id="APP">%s</xliff:g>"</string>
<string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> : <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
<string name="accessibility_notification_dismissed" msgid="854211387186306927">"Notification masquée"</string>
@@ -236,8 +238,7 @@
<string name="gps_notification_found_text" msgid="4619274244146446464">"Position définie par GPS"</string>
<string name="accessibility_location_active" msgid="2427290146138169014">"Demandes de localisation actives"</string>
<string name="accessibility_clear_all" msgid="5235938559247164925">"Supprimer toutes les notifications"</string>
- <!-- no translation found for notification_group_overflow_indicator (1863231301642314183) -->
- <skip />
+ <string name="notification_group_overflow_indicator" msgid="1863231301642314183">"<xliff:g id="NUMBER">%s</xliff:g> autres"</string>
<string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"Paramètres de notification"</string>
<string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"Paramètres de <xliff:g id="APP_NAME">%s</xliff:g>"</string>
<string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"L\'écran pivote automatiquement."</string>
@@ -310,8 +311,7 @@
<string name="recents_search_bar_label" msgid="8074997400187836677">"rechercher"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"Impossible de lancer <xliff:g id="APP">%s</xliff:g>."</string>
<string name="recents_launch_disabled_message" msgid="1624523193008871793">"L\'application <xliff:g id="APP">%s</xliff:g> est désactivée en mode sécurisé."</string>
- <string name="recents_history_button_label" msgid="5153358867807604821">"Historique"</string>
- <string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Effacer"</string>
+ <string name="recents_stack_action_button_label" msgid="6593727103310426253">"Tout effacer"</string>
<string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"Application incompatible avec le mode multifenêtre."</string>
<string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"Application incompatible avec le mode multifenêtre"</string>
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Séparation horizontale"</string>
@@ -480,8 +480,7 @@
<string name="notification_importance_max" msgid="5806278962376556491">"Afficher en haut de la liste des notifications, afficher sur l\'écran et émettre un son"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Plus de paramètres"</string>
<string name="notification_done" msgid="5279426047273930175">"Terminé"</string>
- <!-- no translation found for notification_gear_accessibility (94429150213089611) -->
- <skip />
+ <string name="notification_gear_accessibility" msgid="94429150213089611">"Commandes de notification de l\'application <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="color_and_appearance" msgid="1254323855964993144">"Couleur et apparence"</string>
<string name="night_mode" msgid="3540405868248625488">"Mode Nuit"</string>
<string name="calibrate_display" msgid="5974642573432039217">"Calibrer l\'affichage"</string>
@@ -501,10 +500,48 @@
<string name="battery_detail_charging_summary" msgid="1279095653533044008">"L\'économiseur de batterie n\'est pas disponible lorsque l\'appareil est en charge."</string>
<string name="battery_detail_switch_title" msgid="6285872470260795421">"Économiseur de batterie"</string>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"Limite les performances et les données en arrière-plan."</string>
+ <string name="keyboard_key_button_template" msgid="6230056639734377300">"Bouton <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="keyboard_key_home" msgid="2243500072071305073">"Accueil"</string>
+ <string name="keyboard_key_back" msgid="2337450286042721351">"Précédent"</string>
+ <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"Vers le haut"</string>
+ <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"Vers le bas"</string>
+ <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"Vers la gauche"</string>
+ <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"Vers la droite"</string>
+ <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"Centre"</string>
+ <string name="keyboard_key_tab" msgid="3871485650463164476">"Tabulation"</string>
+ <string name="keyboard_key_space" msgid="2499861316311153293">"Espace"</string>
+ <string name="keyboard_key_enter" msgid="5739632123216118137">"Entrée"</string>
+ <string name="keyboard_key_backspace" msgid="1559580097512385854">"Retour arrière"</string>
+ <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"Lire ou suspendre la lecture"</string>
+ <string name="keyboard_key_media_stop" msgid="2859963958595908962">"Arrêter"</string>
+ <string name="keyboard_key_media_next" msgid="1894394911630345607">"Suivant"</string>
+ <string name="keyboard_key_media_previous" msgid="4256072387192967261">"Précédent"</string>
+ <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"Retour arrière"</string>
+ <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"Avance rapide"</string>
+ <string name="keyboard_key_page_up" msgid="5654098530106845603">"Page précédente"</string>
+ <string name="keyboard_key_page_down" msgid="8720502083731906136">"Page suivante"</string>
+ <string name="keyboard_key_forward_del" msgid="1391451334716490176">"Supprimer"</string>
+ <string name="keyboard_key_move_home" msgid="2765693292069487486">"Accueil"</string>
+ <string name="keyboard_key_move_end" msgid="5901174332047975247">"Fin"</string>
+ <string name="keyboard_key_insert" msgid="8530501581636082614">"Insérer"</string>
+ <string name="keyboard_key_num_lock" msgid="5052537581246772117">"Verr Num"</string>
+ <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"Pavé numérique <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"Système"</string>
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Accueil"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Récents"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Précédent"</string>
+ <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Notifications"</string>
+ <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"Raccourcis clavier"</string>
+ <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"Changer le mode de saisie"</string>
+ <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"Applications"</string>
+ <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"Assistance"</string>
+ <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"Navigateur"</string>
+ <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"Contacts"</string>
+ <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"Messagerie"</string>
+ <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"Messagerie instantanée"</string>
+ <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"Musique"</string>
+ <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+ <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"Agenda"</string>
<string name="tuner_full_zen_title" msgid="4540823317772234308">"Afficher avec les commandes de volume"</string>
<string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Ne pas déranger"</string>
<string name="volume_dnd_silent" msgid="4363882330723050727">"Raccourci des boutons de volume"</string>
@@ -559,4 +596,14 @@
<string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Déplacer vers le haut"</string>
<string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Déplacer vers la gauche"</string>
<string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Déplacer vers la droite"</string>
+ <string name="forced_resizable_info_text" msgid="7591061837558867999">"Il est possible que l\'application ne fonctionne pas en mode multifenêtre."</string>
+ <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"Position <xliff:g id="POSITION">%1$d</xliff:g>, \"<xliff:g id="TILE_NAME">%2$s</xliff:g>\". Appuyer deux fois pour modifier."</string>
+ <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. Appuyer deux fois pour ajouter."</string>
+ <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"Position <xliff:g id="POSITION">%1$d</xliff:g>. Appuyer deux fois pour sélectionner."</string>
+ <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"Déplacer \"<xliff:g id="TILE_NAME">%1$s</xliff:g>\""</string>
+ <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"Supprimer \"<xliff:g id="TILE_NAME">%1$s</xliff:g>\""</string>
+ <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"Le bloc \"<xliff:g id="TILE_NAME">%1$s</xliff:g>\" a bien été ajouté à la position <xliff:g id="POSITION">%2$d</xliff:g>."</string>
+ <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"Le bloc \"<xliff:g id="TILE_NAME">%1$s</xliff:g>\" a bien été supprimé."</string>
+ <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"Le bloc \"<xliff:g id="TILE_NAME">%1$s</xliff:g>\" a bien été déplacé à la position <xliff:g id="POSITION">%2$d</xliff:g>."</string>
+ <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Éditeur de configuration rapide."</string>
</resources>
diff --git a/packages/SystemUI/res/values-fr/strings_tv.xml b/packages/SystemUI/res/values-fr/strings_tv.xml
index 68c4dcb..0478eea 100644
--- a/packages/SystemUI/res/values-fr/strings_tv.xml
+++ b/packages/SystemUI/res/values-fr/strings_tv.xml
@@ -26,6 +26,5 @@
<string name="pip_hold_home" msgid="340086535668778109">"Appui long "<b>"ACCUEIL"</b>" pour contrôler PIP"</string>
<string name="pip_onboarding_description" msgid="2882896641362814195">"Appuyez de manière prolongée sur le bouton ACCUEIL pour contrôler le mode PIP."</string>
<string name="pip_onboarding_button" msgid="3957426748484904611">"OK"</string>
- <!-- no translation found for recents_tv_dismiss (3555093879593377731) -->
- <skip />
+ <string name="recents_tv_dismiss" msgid="3555093879593377731">"Ignorer"</string>
</resources>
diff --git a/packages/SystemUI/res/values-gl-rES/strings.xml b/packages/SystemUI/res/values-gl-rES/strings.xml
index 1474acf..c8f6649 100644
--- a/packages/SystemUI/res/values-gl-rES/strings.xml
+++ b/packages/SystemUI/res/values-gl-rES/strings.xml
@@ -168,6 +168,8 @@
<string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Rexeitar <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"Rexeitouse <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Rexeitáronse todas as aplicacións recentes."</string>
+ <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+ <skip />
<string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Iniciando <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
<string name="accessibility_notification_dismissed" msgid="854211387186306927">"Notificación rexeitada"</string>
@@ -236,8 +238,7 @@
<string name="gps_notification_found_text" msgid="4619274244146446464">"Localización establecida polo GPS"</string>
<string name="accessibility_location_active" msgid="2427290146138169014">"Solicitudes de localización activas"</string>
<string name="accessibility_clear_all" msgid="5235938559247164925">"Eliminar todas as notificacións."</string>
- <!-- no translation found for notification_group_overflow_indicator (1863231301642314183) -->
- <skip />
+ <string name="notification_group_overflow_indicator" msgid="1863231301642314183">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string>
<string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"Configuración das notificacións"</string>
<string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"Configuración de <xliff:g id="APP_NAME">%s</xliff:g>"</string>
<string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"A pantalla xirará automaticamente."</string>
@@ -310,8 +311,7 @@
<string name="recents_search_bar_label" msgid="8074997400187836677">"buscar"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"Non foi posible iniciar <xliff:g id="APP">%s</xliff:g>."</string>
<string name="recents_launch_disabled_message" msgid="1624523193008871793">"A aplicación <xliff:g id="APP">%s</xliff:g> está desactivada no modo seguro"</string>
- <string name="recents_history_button_label" msgid="5153358867807604821">"Historial"</string>
- <string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Borrar"</string>
+ <string name="recents_stack_action_button_label" msgid="6593727103310426253">"Borrar todo"</string>
<string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"Esta aplicación non é compatible con varias ventás"</string>
<string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"A aplicación non é compatible con varias ventás"</string>
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Dividir en horizontal"</string>
@@ -480,8 +480,7 @@
<string name="notification_importance_max" msgid="5806278962376556491">"Mostrar na parte superior da lista de notificacións, amosar na pantalla e permitir que emita son"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Máis opcións"</string>
<string name="notification_done" msgid="5279426047273930175">"Feito"</string>
- <!-- no translation found for notification_gear_accessibility (94429150213089611) -->
- <skip />
+ <string name="notification_gear_accessibility" msgid="94429150213089611">"Controis de notificacións de <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="color_and_appearance" msgid="1254323855964993144">"Cor e aspecto"</string>
<string name="night_mode" msgid="3540405868248625488">"Modo nocturno"</string>
<string name="calibrate_display" msgid="5974642573432039217">"Calibrar pantalla"</string>
@@ -501,10 +500,60 @@
<string name="battery_detail_charging_summary" msgid="1279095653533044008">"A función aforro de batería non está dispoñible durante a carga"</string>
<string name="battery_detail_switch_title" msgid="6285872470260795421">"Aforro de batería"</string>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"Reduce o rendemento e os datos en segundo plano"</string>
+ <string name="keyboard_key_button_template" msgid="6230056639734377300">"Botón <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="keyboard_key_home" msgid="2243500072071305073">"Inicio"</string>
+ <string name="keyboard_key_back" msgid="2337450286042721351">"Volver"</string>
+ <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"Arriba"</string>
+ <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"Abaixo"</string>
+ <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"Esquerda"</string>
+ <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"Dereita"</string>
+ <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"Centro"</string>
+ <string name="keyboard_key_tab" msgid="3871485650463164476">"Tabulador"</string>
+ <string name="keyboard_key_space" msgid="2499861316311153293">"Espazo"</string>
+ <string name="keyboard_key_enter" msgid="5739632123216118137">"Intro"</string>
+ <string name="keyboard_key_backspace" msgid="1559580097512385854">"Retroceso"</string>
+ <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"Reproducir/Pausar"</string>
+ <string name="keyboard_key_media_stop" msgid="2859963958595908962">"Deter"</string>
+ <string name="keyboard_key_media_next" msgid="1894394911630345607">"Seguinte"</string>
+ <string name="keyboard_key_media_previous" msgid="4256072387192967261">"Anterior"</string>
+ <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"Rebobinar"</string>
+ <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"Avance rápido"</string>
+ <string name="keyboard_key_page_up" msgid="5654098530106845603">"Re Páx"</string>
+ <string name="keyboard_key_page_down" msgid="8720502083731906136">"Av Páx"</string>
+ <string name="keyboard_key_forward_del" msgid="1391451334716490176">"Supr"</string>
+ <string name="keyboard_key_move_home" msgid="2765693292069487486">"Inicio"</string>
+ <string name="keyboard_key_move_end" msgid="5901174332047975247">"Fin"</string>
+ <string name="keyboard_key_insert" msgid="8530501581636082614">"Inserir"</string>
+ <string name="keyboard_key_num_lock" msgid="5052537581246772117">"Bloqueo numérico"</string>
+ <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"Teclado numérico <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"Sistema"</string>
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Inicio"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Recentes"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Volver"</string>
+ <!-- no translation found for keyboard_shortcut_group_system_notifications (8366964080041773224) -->
+ <skip />
+ <!-- no translation found for keyboard_shortcut_group_system_shortcuts_helper (4892255911160332762) -->
+ <skip />
+ <!-- no translation found for keyboard_shortcut_group_system_switch_input (2334164096341310324) -->
+ <skip />
+ <!-- no translation found for keyboard_shortcut_group_applications (9129465955073449206) -->
+ <skip />
+ <!-- no translation found for keyboard_shortcut_group_applications_assist (9095441910537146013) -->
+ <skip />
+ <!-- no translation found for keyboard_shortcut_group_applications_browser (6465985474000766533) -->
+ <skip />
+ <!-- no translation found for keyboard_shortcut_group_applications_contacts (2064197111278436375) -->
+ <skip />
+ <!-- no translation found for keyboard_shortcut_group_applications_email (6257036897441939004) -->
+ <skip />
+ <!-- no translation found for keyboard_shortcut_group_applications_im (1892749399083161405) -->
+ <skip />
+ <!-- no translation found for keyboard_shortcut_group_applications_music (4775559515850922780) -->
+ <skip />
+ <!-- no translation found for keyboard_shortcut_group_applications_youtube (6555453761294723317) -->
+ <skip />
+ <!-- no translation found for keyboard_shortcut_group_applications_calendar (9043614299194991263) -->
+ <skip />
<string name="tuner_full_zen_title" msgid="4540823317772234308">"Mostrar cos controis de volume"</string>
<string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Non molestar"</string>
<string name="volume_dnd_silent" msgid="4363882330723050727">"Atallo dos botóns de volume"</string>
@@ -559,4 +608,14 @@
<string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Subir"</string>
<string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Mover á esquerda"</string>
<string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Mover á dereita"</string>
+ <string name="forced_resizable_info_text" msgid="7591061837558867999">"Pode que a aplicación non funcione con varias ventás."</string>
+ <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"Posición <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>. Toca dúas veces o elemento para editalo."</string>
+ <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. Toca dúas veces o elemento para engadilo"</string>
+ <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"Posición <xliff:g id="POSITION">%1$d</xliff:g>. Toca dúas veces o elemento para seleccionalo."</string>
+ <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"Move <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"Elimina <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="TILE_NAME">%1$s</xliff:g> engadiuse á posición <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+ <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"Eliminouse <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="TILE_NAME">%1$s</xliff:g> moveuse á posición <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+ <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Editor de configuración rápida."</string>
</resources>
diff --git a/packages/SystemUI/res/values-gl-rES/strings_tv.xml b/packages/SystemUI/res/values-gl-rES/strings_tv.xml
index 11d2d4c..d43d8cc 100644
--- a/packages/SystemUI/res/values-gl-rES/strings_tv.xml
+++ b/packages/SystemUI/res/values-gl-rES/strings_tv.xml
@@ -26,6 +26,5 @@
<string name="pip_hold_home" msgid="340086535668778109">"Manter premido "<b>"INICIO"</b>" para controlar PIP"</string>
<string name="pip_onboarding_description" msgid="2882896641362814195">"Mantén premido o botón de INICIO para controlar PIP"</string>
<string name="pip_onboarding_button" msgid="3957426748484904611">"De acordo"</string>
- <!-- no translation found for recents_tv_dismiss (3555093879593377731) -->
- <skip />
+ <string name="recents_tv_dismiss" msgid="3555093879593377731">"Ignorar"</string>
</resources>
diff --git a/packages/SystemUI/res/values-gu-rIN/strings.xml b/packages/SystemUI/res/values-gu-rIN/strings.xml
index 7b64214..ef6a49c 100644
--- a/packages/SystemUI/res/values-gu-rIN/strings.xml
+++ b/packages/SystemUI/res/values-gu-rIN/strings.xml
@@ -168,6 +168,8 @@
<string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"<xliff:g id="APP">%s</xliff:g> કાઢી નાખો."</string>
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> કાઢી નાખી."</string>
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"તમામ તાજેતરની એપ્લિકેશનો કાઢી નાખી."</string>
+ <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+ <skip />
<string name="accessibility_recents_item_launched" msgid="7616039892382525203">"<xliff:g id="APP">%s</xliff:g> પ્રારંભ કરી રહ્યું છે."</string>
<string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
<string name="accessibility_notification_dismissed" msgid="854211387186306927">"સૂચના કાઢી નાખી."</string>
@@ -309,8 +311,7 @@
<string name="recents_search_bar_label" msgid="8074997400187836677">"શોધ"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g> પ્રારંભ કરી શકાયું નથી."</string>
<string name="recents_launch_disabled_message" msgid="1624523193008871793">"સુરક્ષિત મોડમાં <xliff:g id="APP">%s</xliff:g> અક્ષમ કરેલ છે."</string>
- <string name="recents_history_button_label" msgid="5153358867807604821">"ઇતિહાસ"</string>
- <string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"સાફ કરો"</string>
+ <string name="recents_stack_action_button_label" msgid="6593727103310426253">"બધું સાફ કરો"</string>
<string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"આ ઍપ્લિકેશન મલ્ટિ-વિંડોનું સમર્થન કરતી નથી"</string>
<string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"ઍપ્લિકેશન મલ્ટિ-વિંડોનું સમર્થન કરતી નથી"</string>
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"આડું વિભક્ત કરો"</string>
@@ -499,10 +500,48 @@
<string name="battery_detail_charging_summary" msgid="1279095653533044008">"ચાર્જિંગ દરમિયાન બૅટરી બચતકર્તા ઉપલબ્ધ નથી"</string>
<string name="battery_detail_switch_title" msgid="6285872470260795421">"બૅટરી બચતકર્તા"</string>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"પ્રદર્શન અને પૃષ્ઠભૂમિ ડેટા ઘટાડે છે"</string>
+ <string name="keyboard_key_button_template" msgid="6230056639734377300">"બટન <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="keyboard_key_home" msgid="2243500072071305073">"Home"</string>
+ <string name="keyboard_key_back" msgid="2337450286042721351">"Back"</string>
+ <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"Up"</string>
+ <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"Down"</string>
+ <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"Left"</string>
+ <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"Right"</string>
+ <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"Center"</string>
+ <string name="keyboard_key_tab" msgid="3871485650463164476">"Tab"</string>
+ <string name="keyboard_key_space" msgid="2499861316311153293">"Space"</string>
+ <string name="keyboard_key_enter" msgid="5739632123216118137">"Enter"</string>
+ <string name="keyboard_key_backspace" msgid="1559580097512385854">"Backspace"</string>
+ <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"Play/Pause"</string>
+ <string name="keyboard_key_media_stop" msgid="2859963958595908962">"Stop"</string>
+ <string name="keyboard_key_media_next" msgid="1894394911630345607">"Next"</string>
+ <string name="keyboard_key_media_previous" msgid="4256072387192967261">"Previous"</string>
+ <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"Rewind"</string>
+ <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"Fast Forward"</string>
+ <string name="keyboard_key_page_up" msgid="5654098530106845603">"Page Up"</string>
+ <string name="keyboard_key_page_down" msgid="8720502083731906136">"Page Down"</string>
+ <string name="keyboard_key_forward_del" msgid="1391451334716490176">"Delete"</string>
+ <string name="keyboard_key_move_home" msgid="2765693292069487486">"Home"</string>
+ <string name="keyboard_key_move_end" msgid="5901174332047975247">"End"</string>
+ <string name="keyboard_key_insert" msgid="8530501581636082614">"Insert"</string>
+ <string name="keyboard_key_num_lock" msgid="5052537581246772117">"Num Lock"</string>
+ <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"Numpad <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"સિસ્ટમ"</string>
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"હોમ"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"તાજેતરના"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"પાછળ"</string>
+ <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"સૂચનાઓ"</string>
+ <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"કીબોર્ડ શૉર્ટકટ્સ"</string>
+ <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"ઇનપુટ પદ્ધતિ સ્વિચ કરો"</string>
+ <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"ઍપ્લિકેશનો"</string>
+ <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"સહાય"</string>
+ <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"બ્રાઉઝર"</string>
+ <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"સંપર્કો"</string>
+ <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"ઇમેઇલ"</string>
+ <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"IM"</string>
+ <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"સંગીત"</string>
+ <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+ <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"કૅલેન્ડર"</string>
<string name="tuner_full_zen_title" msgid="4540823317772234308">"વૉલ્યૂમ નિયંત્રણ સાથે બતાવો"</string>
<string name="volume_and_do_not_disturb" msgid="3373784330208603030">"ખલેલ પાડશો નહીં"</string>
<string name="volume_dnd_silent" msgid="4363882330723050727">"વૉલ્યૂમ બટન્સ શૉર્ટકટ"</string>
@@ -557,4 +596,14 @@
<string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"ઉપર ખસેડો"</string>
<string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"ડાબે ખસેડો"</string>
<string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"જમણે ખસેડો"</string>
+ <string name="forced_resizable_info_text" msgid="7591061837558867999">"બહુ-વિંડો સાથે અૅપ્લિકેશન કદાચ કામ ન કરે"</string>
+ <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"સ્થિતિ <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>. સંપાદિત કરવા માટે બે વાર ટૅપ કરો."</string>
+ <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. ઉમેરવા માટે બે વાર ટૅપ કરો."</string>
+ <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"સ્થિતિ <xliff:g id="POSITION">%1$d</xliff:g>. પસંદ કરવા માટે બે વાર ટૅપ કરો."</string>
+ <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"<xliff:g id="TILE_NAME">%1$s</xliff:g> ખસેડો"</string>
+ <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"<xliff:g id="TILE_NAME">%1$s</xliff:g> દૂર કરો"</string>
+ <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="POSITION">%2$d</xliff:g> સ્થિતિ પર <xliff:g id="TILE_NAME">%1$s</xliff:g> ઉમેર્યું છે"</string>
+ <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"<xliff:g id="TILE_NAME">%1$s</xliff:g> દૂર કરવામાં આવ્યું છે"</string>
+ <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="TILE_NAME">%1$s</xliff:g> ને <xliff:g id="POSITION">%2$d</xliff:g> સ્થિતિ પર ખસેડ્યું"</string>
+ <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"ઝડપી સેટિંગ્સ સંપાદક."</string>
</resources>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index 84c073d..1ba0caf 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -168,6 +168,8 @@
<string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"<xliff:g id="APP">%s</xliff:g> को ख़ारिज करें."</string>
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> खा़रिज कर दिया गया."</string>
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"हाल ही के सभी ऐप्लिकेशन ख़ारिज कर दिए गए."</string>
+ <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+ <skip />
<string name="accessibility_recents_item_launched" msgid="7616039892382525203">"<xliff:g id="APP">%s</xliff:g> प्रारंभ हो रहा है."</string>
<string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
<string name="accessibility_notification_dismissed" msgid="854211387186306927">"नोटिफिकेशन खारिज की गई."</string>
@@ -309,8 +311,7 @@
<string name="recents_search_bar_label" msgid="8074997400187836677">"खोज"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g> प्रारंभ नहीं किया जा सका."</string>
<string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g> को सुरक्षित-मोड में अक्षम किया गया."</string>
- <string name="recents_history_button_label" msgid="5153358867807604821">"इतिहास"</string>
- <string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"साफ़ करें"</string>
+ <string name="recents_stack_action_button_label" msgid="6593727103310426253">"Clear all"</string>
<string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"यह ऐप्लिकेशन एकाधिक विंडो का समर्थन नहीं करता है"</string>
<string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"ऐप्लिकेशन एकाधिक विंडो का समर्थन नहीं करता है"</string>
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"क्षैतिज रूप से विभाजित करें"</string>
@@ -499,10 +500,48 @@
<string name="battery_detail_charging_summary" msgid="1279095653533044008">"चार्ज किए जाने के दौरान बैटरी सेवर उपलब्ध नहीं है"</string>
<string name="battery_detail_switch_title" msgid="6285872470260795421">"बैटरी सेवर"</string>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"निष्पादन और पृष्ठभूमि डेटा को कम करता है"</string>
+ <string name="keyboard_key_button_template" msgid="6230056639734377300">"बटन <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="keyboard_key_home" msgid="2243500072071305073">"Home"</string>
+ <string name="keyboard_key_back" msgid="2337450286042721351">"Back"</string>
+ <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"ऊपर तीर"</string>
+ <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"नीचे तीर"</string>
+ <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"बायां तीर"</string>
+ <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"दायां तीर"</string>
+ <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"मध्य तीर"</string>
+ <string name="keyboard_key_tab" msgid="3871485650463164476">"Tab"</string>
+ <string name="keyboard_key_space" msgid="2499861316311153293">"Space"</string>
+ <string name="keyboard_key_enter" msgid="5739632123216118137">"Enter"</string>
+ <string name="keyboard_key_backspace" msgid="1559580097512385854">"Backspace"</string>
+ <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"Play/Pause"</string>
+ <string name="keyboard_key_media_stop" msgid="2859963958595908962">"Stop"</string>
+ <string name="keyboard_key_media_next" msgid="1894394911630345607">"Next"</string>
+ <string name="keyboard_key_media_previous" msgid="4256072387192967261">"Previous"</string>
+ <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"Rewind"</string>
+ <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"Fast Forward"</string>
+ <string name="keyboard_key_page_up" msgid="5654098530106845603">"Page Up"</string>
+ <string name="keyboard_key_page_down" msgid="8720502083731906136">"Page Down"</string>
+ <string name="keyboard_key_forward_del" msgid="1391451334716490176">"Delete"</string>
+ <string name="keyboard_key_move_home" msgid="2765693292069487486">"Home"</string>
+ <string name="keyboard_key_move_end" msgid="5901174332047975247">"End"</string>
+ <string name="keyboard_key_insert" msgid="8530501581636082614">"Insert"</string>
+ <string name="keyboard_key_num_lock" msgid="5052537581246772117">"Num Lock"</string>
+ <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"Numpad <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"सिस्टम"</string>
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"होम"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"हाल ही के"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"वापस जाएं"</string>
+ <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"नोटिफ़िकेशन"</string>
+ <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"कीबोर्ड शॉर्टकट"</string>
+ <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"इनपुट पद्धति बदलें"</string>
+ <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"ऐप्लिकेशन"</string>
+ <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"सहायक"</string>
+ <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"ब्राउज़र"</string>
+ <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"संपर्क"</string>
+ <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"ईमेल"</string>
+ <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"IM"</string>
+ <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"संगीत"</string>
+ <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+ <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"कैलेंडर"</string>
<string name="tuner_full_zen_title" msgid="4540823317772234308">"वॉल्यूम नियंत्रणों के साथ दिखाएं"</string>
<string name="volume_and_do_not_disturb" msgid="3373784330208603030">"परेशान न करें"</string>
<string name="volume_dnd_silent" msgid="4363882330723050727">"वॉल्यूम बटन का शॉर्टकट"</string>
@@ -557,4 +596,14 @@
<string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"ऊपर ले जाएं"</string>
<string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"बाएं ले जाएं"</string>
<string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"दाएं ले जाएं"</string>
+ <string name="forced_resizable_info_text" msgid="7591061837558867999">"हो सकता है कि ऐप्लिकेशन एकाधिक विंडो के साथ काम ना करे"</string>
+ <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"स्थिति <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>. संपादित करने के लिए डबल टैप करें."</string>
+ <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. जोड़ने के लिए डबल टैप करें."</string>
+ <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"स्थिति <xliff:g id="POSITION">%1$d</xliff:g>. चुनने के लिए डबल टैप करें."</string>
+ <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"<xliff:g id="TILE_NAME">%1$s</xliff:g> को ले जाएं"</string>
+ <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"<xliff:g id="TILE_NAME">%1$s</xliff:g> निकालें"</string>
+ <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="TILE_NAME">%1$s</xliff:g> को <xliff:g id="POSITION">%2$d</xliff:g> स्थिति में जोड़ा गया"</string>
+ <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"<xliff:g id="TILE_NAME">%1$s</xliff:g> निकाल दिया गया है"</string>
+ <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="TILE_NAME">%1$s</xliff:g> को <xliff:g id="POSITION">%2$d</xliff:g> स्थिति में ले जाया गया"</string>
+ <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"त्वरित सेटिंग संपादक."</string>
</resources>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index e69ad31..81c6276 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -169,6 +169,8 @@
<string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Odbacivanje aplikacije <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"Aplikacija <xliff:g id="APP">%s</xliff:g> odbačena je."</string>
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Odbačene su sve nedavne aplikacije."</string>
+ <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+ <skip />
<string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Pokretanje aplikacije <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
<string name="accessibility_notification_dismissed" msgid="854211387186306927">"Obavijest je odbačena."</string>
@@ -237,8 +239,7 @@
<string name="gps_notification_found_text" msgid="4619274244146446464">"Lokaciju utvrdio GPS"</string>
<string name="accessibility_location_active" msgid="2427290146138169014">"Zahtjevi za lokaciju aktivni su"</string>
<string name="accessibility_clear_all" msgid="5235938559247164925">"Brisanje svih obavijesti."</string>
- <!-- no translation found for notification_group_overflow_indicator (1863231301642314183) -->
- <skip />
+ <string name="notification_group_overflow_indicator" msgid="1863231301642314183">"još <xliff:g id="NUMBER">%s</xliff:g>"</string>
<string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"Postavke obavijesti"</string>
<string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"Postavke aplikacije <xliff:g id="APP_NAME">%s</xliff:g>"</string>
<string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Zaslon će se automatski zakrenuti."</string>
@@ -311,8 +312,7 @@
<string name="recents_search_bar_label" msgid="8074997400187836677">"pretraži"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"Aplikacija <xliff:g id="APP">%s</xliff:g> nije pokrenuta."</string>
<string name="recents_launch_disabled_message" msgid="1624523193008871793">"Aplikacija <xliff:g id="APP">%s</xliff:g> onemogućena je u sigurnom načinu."</string>
- <string name="recents_history_button_label" msgid="5153358867807604821">"Povijest"</string>
- <string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Izbriši"</string>
+ <string name="recents_stack_action_button_label" msgid="6593727103310426253">"Izbriši sve"</string>
<string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"Ta aplikacija ne podržava više prozora"</string>
<string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"Aplikacija ne podržava više prozora"</string>
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Podijeli vodoravno"</string>
@@ -481,8 +481,7 @@
<string name="notification_importance_max" msgid="5806278962376556491">"Prikaži pri vrhu popisa obavijesti, prikaži na zaslonu i dopusti zvuk"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Više postavki"</string>
<string name="notification_done" msgid="5279426047273930175">"Gotovo"</string>
- <!-- no translation found for notification_gear_accessibility (94429150213089611) -->
- <skip />
+ <string name="notification_gear_accessibility" msgid="94429150213089611">"Kontrole obavijesti za aplikaciju <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="color_and_appearance" msgid="1254323855964993144">"Boja i izgled"</string>
<string name="night_mode" msgid="3540405868248625488">"Noćni način rada"</string>
<string name="calibrate_display" msgid="5974642573432039217">"Kalibriranje zaslona"</string>
@@ -502,10 +501,48 @@
<string name="battery_detail_charging_summary" msgid="1279095653533044008">"Štednja baterije nije dostupna tijekom punjenja"</string>
<string name="battery_detail_switch_title" msgid="6285872470260795421">"Štednja baterije"</string>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"Smanjuje količinu rada i pozadinske podatke"</string>
+ <string name="keyboard_key_button_template" msgid="6230056639734377300">"Tipka <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="keyboard_key_home" msgid="2243500072071305073">"Početak"</string>
+ <string name="keyboard_key_back" msgid="2337450286042721351">"Natrag"</string>
+ <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"Gore"</string>
+ <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"Dolje"</string>
+ <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"Lijevo"</string>
+ <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"Desno"</string>
+ <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"Sredina"</string>
+ <string name="keyboard_key_tab" msgid="3871485650463164476">"Tabulator"</string>
+ <string name="keyboard_key_space" msgid="2499861316311153293">"Razmaknica"</string>
+ <string name="keyboard_key_enter" msgid="5739632123216118137">"Unos"</string>
+ <string name="keyboard_key_backspace" msgid="1559580097512385854">"Povratna tipka"</string>
+ <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"Reprodukcija/pauza"</string>
+ <string name="keyboard_key_media_stop" msgid="2859963958595908962">"Zaustavi"</string>
+ <string name="keyboard_key_media_next" msgid="1894394911630345607">"Sljedeće"</string>
+ <string name="keyboard_key_media_previous" msgid="4256072387192967261">"Prethodno"</string>
+ <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"Unatrag"</string>
+ <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"Brzo naprijed"</string>
+ <string name="keyboard_key_page_up" msgid="5654098530106845603">"Stranica prema gore"</string>
+ <string name="keyboard_key_page_down" msgid="8720502083731906136">"Stranica prema dolje"</string>
+ <string name="keyboard_key_forward_del" msgid="1391451334716490176">"Izbriši"</string>
+ <string name="keyboard_key_move_home" msgid="2765693292069487486">"Početak"</string>
+ <string name="keyboard_key_move_end" msgid="5901174332047975247">"Kraj"</string>
+ <string name="keyboard_key_insert" msgid="8530501581636082614">"Umetni"</string>
+ <string name="keyboard_key_num_lock" msgid="5052537581246772117">"Zaključavanje brojčane tipkovnice"</string>
+ <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"Brojčana tipkovnica <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"Sustav"</string>
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Početni zaslon"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Najnovije"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Natrag"</string>
+ <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Obavijesti"</string>
+ <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"Tipkovni prečaci"</string>
+ <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"Promjena načina unosa"</string>
+ <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"Aplikacije"</string>
+ <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"Pomoć"</string>
+ <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"Preglednik"</string>
+ <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"Kontakti"</string>
+ <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"E-pošta"</string>
+ <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"Izravna poruka"</string>
+ <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"Glazba"</string>
+ <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+ <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"Kalendar"</string>
<string name="tuner_full_zen_title" msgid="4540823317772234308">"Prikaži s kontrolama glasnoće"</string>
<string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Ne uznemiravaj"</string>
<string name="volume_dnd_silent" msgid="4363882330723050727">"Prečac tipki za glasnoću"</string>
@@ -560,4 +597,14 @@
<string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Pomakni prema gore"</string>
<string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Pomakni ulijevo"</string>
<string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Pomakni udesno"</string>
+ <string name="forced_resizable_info_text" msgid="7591061837558867999">"Aplikacija možda neće funkcionirati uz više prozora"</string>
+ <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"Položaj <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>. Dodirnite dvaput da biste uredili."</string>
+ <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. Dodirnite dvaput da biste dodali."</string>
+ <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"Položaj <xliff:g id="POSITION">%1$d</xliff:g>. Dodirnite dvaput da biste odabrali."</string>
+ <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"Premjesti <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"Ukloni <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"Pločica <xliff:g id="TILE_NAME">%1$s</xliff:g> dodana je na položaj <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+ <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"Pločica <xliff:g id="TILE_NAME">%1$s</xliff:g> uklonjena"</string>
+ <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"Pločica <xliff:g id="TILE_NAME">%1$s</xliff:g> premještena je na položaj <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+ <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Uređivač brzih postavki."</string>
</resources>
diff --git a/packages/SystemUI/res/values-hr/strings_tv.xml b/packages/SystemUI/res/values-hr/strings_tv.xml
index 3d5c8f8..340a613 100644
--- a/packages/SystemUI/res/values-hr/strings_tv.xml
+++ b/packages/SystemUI/res/values-hr/strings_tv.xml
@@ -26,6 +26,5 @@
<string name="pip_hold_home" msgid="340086535668778109">"Držite "<b>"POČETNI"</b>" za PIP"</string>
<string name="pip_onboarding_description" msgid="2882896641362814195">"Pritisnite i zadržite tipku POČETNI ZASLON da biste upravljali slikom u slici"</string>
<string name="pip_onboarding_button" msgid="3957426748484904611">"Shvaćam"</string>
- <!-- no translation found for recents_tv_dismiss (3555093879593377731) -->
- <skip />
+ <string name="recents_tv_dismiss" msgid="3555093879593377731">"Odbaci"</string>
</resources>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index a7d62c3..b7ac8a4 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -168,6 +168,8 @@
<string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"A(z) <xliff:g id="APP">%s</xliff:g> elvetése."</string>
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> eltávolítva."</string>
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Az összes alkalmazás eltávolítva a nemrég használtak közül."</string>
+ <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+ <skip />
<string name="accessibility_recents_item_launched" msgid="7616039892382525203">"A(z) <xliff:g id="APP">%s</xliff:g> indítása."</string>
<string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
<string name="accessibility_notification_dismissed" msgid="854211387186306927">"Értesítés elvetve."</string>
@@ -309,8 +311,7 @@
<string name="recents_search_bar_label" msgid="8074997400187836677">"keresés"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"Nem lehet elindítani a következőt: <xliff:g id="APP">%s</xliff:g>."</string>
<string name="recents_launch_disabled_message" msgid="1624523193008871793">"A(z) <xliff:g id="APP">%s</xliff:g> csökkentett módban ki van kapcsolva."</string>
- <string name="recents_history_button_label" msgid="5153358867807604821">"Előzmények"</string>
- <string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Törlés"</string>
+ <string name="recents_stack_action_button_label" msgid="6593727103310426253">"Összes törlése"</string>
<string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"Ez az alkalmazás nem támogatja a többablakos nézetet"</string>
<string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"Az alkalmazás nem támogatja a többablakos nézetet"</string>
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Osztott vízszintes"</string>
@@ -499,10 +500,48 @@
<string name="battery_detail_charging_summary" msgid="1279095653533044008">"Az Akkumulátorkímélő módot töltés közben nem lehet használni"</string>
<string name="battery_detail_switch_title" msgid="6285872470260795421">"Akkumulátorkímélő mód"</string>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"Csökkenti a teljesítményt és a háttéradatok használatát"</string>
+ <string name="keyboard_key_button_template" msgid="6230056639734377300">"<xliff:g id="NAME">%1$s</xliff:g> gomb"</string>
+ <string name="keyboard_key_home" msgid="2243500072071305073">"Kezdőképernyő"</string>
+ <string name="keyboard_key_back" msgid="2337450286042721351">"Vissza"</string>
+ <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"Fel"</string>
+ <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"Le"</string>
+ <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"Balra"</string>
+ <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"Jobbra"</string>
+ <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"Középre"</string>
+ <string name="keyboard_key_tab" msgid="3871485650463164476">"Tab"</string>
+ <string name="keyboard_key_space" msgid="2499861316311153293">"Szóköz"</string>
+ <string name="keyboard_key_enter" msgid="5739632123216118137">"Enter"</string>
+ <string name="keyboard_key_backspace" msgid="1559580097512385854">"Visszatörlés"</string>
+ <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"Lejátszás/szünet"</string>
+ <string name="keyboard_key_media_stop" msgid="2859963958595908962">"Leállítás"</string>
+ <string name="keyboard_key_media_next" msgid="1894394911630345607">"Következő"</string>
+ <string name="keyboard_key_media_previous" msgid="4256072387192967261">"Előző"</string>
+ <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"Visszatekerés"</string>
+ <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"Gyors előretekerés"</string>
+ <string name="keyboard_key_page_up" msgid="5654098530106845603">"Page Up"</string>
+ <string name="keyboard_key_page_down" msgid="8720502083731906136">"Page Down"</string>
+ <string name="keyboard_key_forward_del" msgid="1391451334716490176">"Delete"</string>
+ <string name="keyboard_key_move_home" msgid="2765693292069487486">"Kezdőképernyő"</string>
+ <string name="keyboard_key_move_end" msgid="5901174332047975247">"End"</string>
+ <string name="keyboard_key_insert" msgid="8530501581636082614">"Insert"</string>
+ <string name="keyboard_key_num_lock" msgid="5052537581246772117">"Num Lock"</string>
+ <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"Numerikus: <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"Rendszer"</string>
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Otthon"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Legutóbbiak"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Vissza"</string>
+ <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Értesítések"</string>
+ <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"Billentyűkódok"</string>
+ <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"Beviteli mód váltása"</string>
+ <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"Alkalmazások"</string>
+ <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"Segédalkalmazás"</string>
+ <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"Böngésző"</string>
+ <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"Névjegyek"</string>
+ <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"E-mail"</string>
+ <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"Azonnali üzenetküldés"</string>
+ <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"Zene"</string>
+ <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+ <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"Naptár"</string>
<string name="tuner_full_zen_title" msgid="4540823317772234308">"Megjelenítés hangerőszabályzóval"</string>
<string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Ne zavarjanak"</string>
<string name="volume_dnd_silent" msgid="4363882330723050727">"A hangerőgombok gyorsbillentyűk"</string>
@@ -557,4 +596,14 @@
<string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Mozgatás felfelé"</string>
<string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Mozgatás balra"</string>
<string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Mozgatás jobbra"</string>
+ <string name="forced_resizable_info_text" msgid="7591061837558867999">"Lehet, hogy az alkalmazás nem működik többablakos nézetben"</string>
+ <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"<xliff:g id="POSITION">%1$d</xliff:g>. pozíció: <xliff:g id="TILE_NAME">%2$s</xliff:g>. Koppintson duplán a szerkesztéshez."</string>
+ <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. Koppintson duplán a hozzáadáshoz."</string>
+ <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"<xliff:g id="POSITION">%1$d</xliff:g>. pozíció. Koppintson duplán a kiválasztáshoz."</string>
+ <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"A(z) <xliff:g id="TILE_NAME">%1$s</xliff:g> áthelyezése"</string>
+ <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"A(z) <xliff:g id="TILE_NAME">%1$s</xliff:g> eltávolítása"</string>
+ <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"A(z) <xliff:g id="TILE_NAME">%1$s</xliff:g> hozzáadva <xliff:g id="POSITION">%2$d</xliff:g>. pozícióban"</string>
+ <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"A(z) <xliff:g id="TILE_NAME">%1$s</xliff:g> eltávolítva"</string>
+ <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"A(z) <xliff:g id="TILE_NAME">%1$s</xliff:g> áthelyezve a(z) <xliff:g id="POSITION">%2$d</xliff:g>. pozícióba"</string>
+ <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Gyorsbeállítások szerkesztője"</string>
</resources>
diff --git a/packages/SystemUI/res/values-hy-rAM/strings.xml b/packages/SystemUI/res/values-hy-rAM/strings.xml
index 79e5268..7e4e01a 100644
--- a/packages/SystemUI/res/values-hy-rAM/strings.xml
+++ b/packages/SystemUI/res/values-hy-rAM/strings.xml
@@ -168,6 +168,8 @@
<string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Անտեսել <xliff:g id="APP">%s</xliff:g>-ը:"</string>
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g>-ը անտեսված է:"</string>
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Բոլոր վերջին հավելվածները հեռացվել են ցուցակից:"</string>
+ <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+ <skip />
<string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Մեկնարկել <xliff:g id="APP">%s</xliff:g>-ը:"</string>
<string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
<string name="accessibility_notification_dismissed" msgid="854211387186306927">"Ծանուցումը անտեսվեց:"</string>
@@ -236,8 +238,7 @@
<string name="gps_notification_found_text" msgid="4619274244146446464">"Տեղադրությունը կարգավորվել է GPS-ի կողմից"</string>
<string name="accessibility_location_active" msgid="2427290146138169014">"Տեղադրության հարցումներն ակտիվ են"</string>
<string name="accessibility_clear_all" msgid="5235938559247164925">"Մաքրել բոլոր ծանուցումները:"</string>
- <!-- no translation found for notification_group_overflow_indicator (1863231301642314183) -->
- <skip />
+ <string name="notification_group_overflow_indicator" msgid="1863231301642314183">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string>
<string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"Ծանուցման կարգավորումներ"</string>
<string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"<xliff:g id="APP_NAME">%s</xliff:g>-ի կարգավորումներ"</string>
<string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Էկրանը ինքնաշխատ կպտտվի:"</string>
@@ -310,8 +311,7 @@
<string name="recents_search_bar_label" msgid="8074997400187836677">"որոնել"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"Հնարավոր չէ գործարկել <xliff:g id="APP">%s</xliff:g>-ը:"</string>
<string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g> հավելվածը անվտանգ ռեժիմում անջատված է:"</string>
- <string name="recents_history_button_label" msgid="5153358867807604821">"Պատմություն"</string>
- <string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Մաքրել"</string>
+ <string name="recents_stack_action_button_label" msgid="6593727103310426253">"Մաքրել բոլորը"</string>
<string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"Այս հավելվածը չի աջակցում բազմապատուհան ռեժիմը"</string>
<string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"Հավելվածը չի աջակցում բազմապատուհան ռեժիմը"</string>
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Հորիզոնական տրոհում"</string>
@@ -480,8 +480,7 @@
<string name="notification_importance_max" msgid="5806278962376556491">"Ցույց տալ ծանուցումների ցանկի վերևում, թռուցիկ ցուցադրել էկրանին և թույլատրել ձայնային ազդանշանը"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Այլ կարգավորումներ"</string>
<string name="notification_done" msgid="5279426047273930175">"Պատրաստ է"</string>
- <!-- no translation found for notification_gear_accessibility (94429150213089611) -->
- <skip />
+ <string name="notification_gear_accessibility" msgid="94429150213089611">"<xliff:g id="APP_NAME">%1$s</xliff:g> հավելվածի ծանուցումների կառավարներ"</string>
<string name="color_and_appearance" msgid="1254323855964993144">"Գույնը և արտաքին տեսքը"</string>
<string name="night_mode" msgid="3540405868248625488">"Գիշերային ռեժիմ"</string>
<string name="calibrate_display" msgid="5974642573432039217">"Չափաբերել էկրանը"</string>
@@ -501,10 +500,48 @@
<string name="battery_detail_charging_summary" msgid="1279095653533044008">"Մարտկոցի տնտեսումը լիցքավորման ժամանակ հասանելի չէ"</string>
<string name="battery_detail_switch_title" msgid="6285872470260795421">"Մարտկոցի տնտեսում"</string>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"Նվազեցնում է ծանրաբեռնվածությունը և ֆոնային տվյալները"</string>
+ <string name="keyboard_key_button_template" msgid="6230056639734377300">"<xliff:g id="NAME">%1$s</xliff:g> կոճակ"</string>
+ <string name="keyboard_key_home" msgid="2243500072071305073">"Գլխավոր էջ"</string>
+ <string name="keyboard_key_back" msgid="2337450286042721351">"Հետ"</string>
+ <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"Վերև"</string>
+ <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"Ներքև"</string>
+ <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"Ձախ"</string>
+ <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"Աջ"</string>
+ <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"Կենտրոն"</string>
+ <string name="keyboard_key_tab" msgid="3871485650463164476">"Tab"</string>
+ <string name="keyboard_key_space" msgid="2499861316311153293">"Բացատ"</string>
+ <string name="keyboard_key_enter" msgid="5739632123216118137">"Մուտք"</string>
+ <string name="keyboard_key_backspace" msgid="1559580097512385854">"Հետշարժ"</string>
+ <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"Նվագարկում/դադար"</string>
+ <string name="keyboard_key_media_stop" msgid="2859963958595908962">"Դադարեցնել"</string>
+ <string name="keyboard_key_media_next" msgid="1894394911630345607">"Հաջորդը"</string>
+ <string name="keyboard_key_media_previous" msgid="4256072387192967261">"Նախորդը"</string>
+ <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"Հետ անցնել"</string>
+ <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"Արագ առաջ անցնել"</string>
+ <string name="keyboard_key_page_up" msgid="5654098530106845603">"Page Up"</string>
+ <string name="keyboard_key_page_down" msgid="8720502083731906136">"Page down"</string>
+ <string name="keyboard_key_forward_del" msgid="1391451334716490176">"Ջնջել"</string>
+ <string name="keyboard_key_move_home" msgid="2765693292069487486">"Գլխավոր էջ"</string>
+ <string name="keyboard_key_move_end" msgid="5901174332047975247">"Վերջ"</string>
+ <string name="keyboard_key_insert" msgid="8530501581636082614">"Տեղադրել"</string>
+ <string name="keyboard_key_num_lock" msgid="5052537581246772117">"Num Lock"</string>
+ <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"Numpad <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"Համակարգ"</string>
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Գլխավոր էջ"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Վերջինները"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Հետ"</string>
+ <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Ծանուցումներ"</string>
+ <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"Ստեղնային դյուրանցումներ"</string>
+ <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"Փոխարկել մուտքագրման եղանակը"</string>
+ <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"Գործադիրներ"</string>
+ <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"Օգնություն"</string>
+ <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"Դիտարկիչ"</string>
+ <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"Կոնտակտներ"</string>
+ <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"Էլփոստ"</string>
+ <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"IM"</string>
+ <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"Երաժշտություն"</string>
+ <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+ <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"Օրացույց"</string>
<string name="tuner_full_zen_title" msgid="4540823317772234308">"Ցույց տալ ձայնի ուժգնության կառավարման տարրերի հետ"</string>
<string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Չընդհատել"</string>
<string name="volume_dnd_silent" msgid="4363882330723050727">"Ձայնի կոճակների դյուրանցում"</string>
@@ -540,8 +577,7 @@
<string name="select_keycode" msgid="7413765103381924584">"Ընտրեք ստեղնաշարի կոճակը"</string>
<string name="preview" msgid="9077832302472282938">"Նախադիտում"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"Քաշեք՝ սալիկներ ավելացնելու համար"</string>
- <!-- no translation found for drag_to_remove_tiles (3361212377437088062) -->
- <skip />
+ <string name="drag_to_remove_tiles" msgid="3361212377437088062">"Քաշեք այստեղ՝ հեռացնելու համար"</string>
<string name="qs_edit" msgid="2232596095725105230">"Փոփոխել"</string>
<string name="tuner_time" msgid="6572217313285536011">"Ժամ"</string>
<string-array name="clock_options">
@@ -560,4 +596,14 @@
<string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Տեղափոխել վերև"</string>
<string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Տեղափոխել ձախ"</string>
<string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Տեղափոխել աջ"</string>
+ <string name="forced_resizable_info_text" msgid="7591061837558867999">"Հավելվածը չի կարող աշխատել բազմապատուհան ռեժիմում"</string>
+ <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"Դիրք <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>: Կրկնակի հպեք՝ փոխելու համար:"</string>
+ <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>: Կրկնակի հպեք՝ ավելացնելու համար:"</string>
+ <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"Դիրք <xliff:g id="POSITION">%1$d</xliff:g>: Կրկնակի հպեք՝ ընտրելու համար:"</string>
+ <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"Տեղափոխել <xliff:g id="TILE_NAME">%1$s</xliff:g> սալիկը"</string>
+ <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"Հեռացնել <xliff:g id="TILE_NAME">%1$s</xliff:g> սալիկը"</string>
+ <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="TILE_NAME">%1$s</xliff:g> սալիկն ավելացվել է <xliff:g id="POSITION">%2$d</xliff:g> դիրքին"</string>
+ <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"<xliff:g id="TILE_NAME">%1$s</xliff:g> սալիկը հեռացվել է"</string>
+ <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="TILE_NAME">%1$s</xliff:g> սալիկը տեղափոխվել է դեպի <xliff:g id="POSITION">%2$d</xliff:g> դիրք"</string>
+ <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Արագ կարգավորումների խմբագրիչ:"</string>
</resources>
diff --git a/packages/SystemUI/res/values-hy-rAM/strings_tv.xml b/packages/SystemUI/res/values-hy-rAM/strings_tv.xml
index dc4c312..5f9c127 100644
--- a/packages/SystemUI/res/values-hy-rAM/strings_tv.xml
+++ b/packages/SystemUI/res/values-hy-rAM/strings_tv.xml
@@ -26,6 +26,5 @@
<string name="pip_hold_home" msgid="340086535668778109">"PIP-ն կառավարելու համար սեղմած պահեք "<b>"HOME"</b>" կոճակը"</string>
<string name="pip_onboarding_description" msgid="2882896641362814195">"PIP-ն կառավարելու համար սեղմեք և պահեք HOME կոճակը"</string>
<string name="pip_onboarding_button" msgid="3957426748484904611">"Պարզ է"</string>
- <!-- no translation found for recents_tv_dismiss (3555093879593377731) -->
- <skip />
+ <string name="recents_tv_dismiss" msgid="3555093879593377731">"Փակել"</string>
</resources>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index 3ac5904..2b51426 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -168,6 +168,8 @@
<string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Menyingkirkan <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> disingkirkan."</string>
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Semua aplikasi terbaru telah ditutup."</string>
+ <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+ <skip />
<string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Memulai <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
<string name="accessibility_notification_dismissed" msgid="854211387186306927">"Notifikasi disingkirkan."</string>
@@ -236,8 +238,7 @@
<string name="gps_notification_found_text" msgid="4619274244146446464">"Lokasi yang disetel oleh GPS"</string>
<string name="accessibility_location_active" msgid="2427290146138169014">"Permintaan lokasi aktif"</string>
<string name="accessibility_clear_all" msgid="5235938559247164925">"Menghapus semua pemberitahuan."</string>
- <!-- no translation found for notification_group_overflow_indicator (1863231301642314183) -->
- <skip />
+ <string name="notification_group_overflow_indicator" msgid="1863231301642314183">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string>
<string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"Setelan pemberitahuan"</string>
<string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"<xliff:g id="APP_NAME">%s</xliff:g> setelan"</string>
<string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Layar akan diputar secara otomatis."</string>
@@ -310,8 +311,7 @@
<string name="recents_search_bar_label" msgid="8074997400187836677">"telusuri"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"Tidak dapat memulai <xliff:g id="APP">%s</xliff:g>."</string>
<string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g> dinonaktifkan dalam mode aman."</string>
- <string name="recents_history_button_label" msgid="5153358867807604821">"Riwayat"</string>
- <string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Hapus"</string>
+ <string name="recents_stack_action_button_label" msgid="6593727103310426253">"Hapus semua"</string>
<string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"Aplikasi ini tidak mendukung multijendela"</string>
<string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"Aplikasi tidak mendukung multijendela"</string>
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Pisahkan Horizontal"</string>
@@ -480,8 +480,7 @@
<string name="notification_importance_max" msgid="5806278962376556491">"Tampilkan di bagian atas daftar notifikasi, muncul di layar, dan izinkan suara"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Setelan lainnya"</string>
<string name="notification_done" msgid="5279426047273930175">"Selesai"</string>
- <!-- no translation found for notification_gear_accessibility (94429150213089611) -->
- <skip />
+ <string name="notification_gear_accessibility" msgid="94429150213089611">"Kontrol notifikasi <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="color_and_appearance" msgid="1254323855964993144">"Warna dan tampilan"</string>
<string name="night_mode" msgid="3540405868248625488">"Mode malam"</string>
<string name="calibrate_display" msgid="5974642573432039217">"Kalibrasi layar"</string>
@@ -501,10 +500,48 @@
<string name="battery_detail_charging_summary" msgid="1279095653533044008">"Penghemat Baterai tidak tersedia selama pengisian daya"</string>
<string name="battery_detail_switch_title" msgid="6285872470260795421">"Penghemat Baterai"</string>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"Mengurangi performa dan data latar belakang"</string>
+ <string name="keyboard_key_button_template" msgid="6230056639734377300">"Tombol <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="keyboard_key_home" msgid="2243500072071305073">"Home"</string>
+ <string name="keyboard_key_back" msgid="2337450286042721351">"Back"</string>
+ <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"Up"</string>
+ <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"Down"</string>
+ <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"Left"</string>
+ <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"Right"</string>
+ <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"Center"</string>
+ <string name="keyboard_key_tab" msgid="3871485650463164476">"Tab"</string>
+ <string name="keyboard_key_space" msgid="2499861316311153293">"Space"</string>
+ <string name="keyboard_key_enter" msgid="5739632123216118137">"Enter"</string>
+ <string name="keyboard_key_backspace" msgid="1559580097512385854">"Backspace"</string>
+ <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"Play/Pause"</string>
+ <string name="keyboard_key_media_stop" msgid="2859963958595908962">"Stop"</string>
+ <string name="keyboard_key_media_next" msgid="1894394911630345607">"Next"</string>
+ <string name="keyboard_key_media_previous" msgid="4256072387192967261">"Previous"</string>
+ <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"Rewind"</string>
+ <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"Fast Forward"</string>
+ <string name="keyboard_key_page_up" msgid="5654098530106845603">"Page Up"</string>
+ <string name="keyboard_key_page_down" msgid="8720502083731906136">"Page Down"</string>
+ <string name="keyboard_key_forward_del" msgid="1391451334716490176">"Delete"</string>
+ <string name="keyboard_key_move_home" msgid="2765693292069487486">"Home"</string>
+ <string name="keyboard_key_move_end" msgid="5901174332047975247">"End"</string>
+ <string name="keyboard_key_insert" msgid="8530501581636082614">"Insert"</string>
+ <string name="keyboard_key_num_lock" msgid="5052537581246772117">"Num Lock"</string>
+ <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"Numpad <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"Sistem"</string>
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Layar Utama"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Terbaru"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Kembali"</string>
+ <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Notifikasi"</string>
+ <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"Pintasan Keyboard"</string>
+ <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"Beralih metode masukan"</string>
+ <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"Aplikasi"</string>
+ <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"Bantuan"</string>
+ <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"Browser"</string>
+ <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"Kontak"</string>
+ <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"Email"</string>
+ <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"IM"</string>
+ <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"Musik"</string>
+ <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+ <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"Kalender"</string>
<string name="tuner_full_zen_title" msgid="4540823317772234308">"Tampilkan dengan kontrol volume"</string>
<string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Jangan ganggu"</string>
<string name="volume_dnd_silent" msgid="4363882330723050727">"Pintasan tombol volume"</string>
@@ -559,4 +596,14 @@
<string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Naikkan"</string>
<string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Pindahkan ke kiri"</string>
<string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Pindahkan ke kanan"</string>
+ <string name="forced_resizable_info_text" msgid="7591061837558867999">"Aplikasi mungkin tidak berfungsi dengan multi-jendela"</string>
+ <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"Posisi <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>. Ketuk dua kali untuk mengedit."</string>
+ <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. Ketuk dua kali untuk menambahkan."</string>
+ <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"Posisi <xliff:g id="POSITION">%1$d</xliff:g>. Ketuk dua kali untuk memilih."</string>
+ <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"Pindahkan <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"Hapus <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="TILE_NAME">%1$s</xliff:g> ditambahkan ke posisi <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+ <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"<xliff:g id="TILE_NAME">%1$s</xliff:g> dihapus"</string>
+ <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="TILE_NAME">%1$s</xliff:g> dpindahkan ke posisi <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+ <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Editor setelan cepat."</string>
</resources>
diff --git a/packages/SystemUI/res/values-in/strings_tv.xml b/packages/SystemUI/res/values-in/strings_tv.xml
index 8e3a5e0..7de1a78 100644
--- a/packages/SystemUI/res/values-in/strings_tv.xml
+++ b/packages/SystemUI/res/values-in/strings_tv.xml
@@ -26,6 +26,5 @@
<string name="pip_hold_home" msgid="340086535668778109">"Tahan "<b>"LAYAR UTAMA"</b>" untuk mengontrol PIP"</string>
<string name="pip_onboarding_description" msgid="2882896641362814195">"Tekan dan tahan tombol LAYAR UTAMA untuk mengontrol PIP"</string>
<string name="pip_onboarding_button" msgid="3957426748484904611">"Mengerti"</string>
- <!-- no translation found for recents_tv_dismiss (3555093879593377731) -->
- <skip />
+ <string name="recents_tv_dismiss" msgid="3555093879593377731">"Tutup"</string>
</resources>
diff --git a/packages/SystemUI/res/values-is-rIS/strings.xml b/packages/SystemUI/res/values-is-rIS/strings.xml
index c063c73..1dc37df 100644
--- a/packages/SystemUI/res/values-is-rIS/strings.xml
+++ b/packages/SystemUI/res/values-is-rIS/strings.xml
@@ -168,6 +168,8 @@
<string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Hunsa <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> vísað frá."</string>
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Öll nýleg forrit fjarlægð."</string>
+ <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+ <skip />
<string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Ræsir <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
<string name="accessibility_notification_dismissed" msgid="854211387186306927">"Tilkynningu lokað."</string>
@@ -236,8 +238,7 @@
<string name="gps_notification_found_text" msgid="4619274244146446464">"Staðsetning valin með GPS"</string>
<string name="accessibility_location_active" msgid="2427290146138169014">"Staðsetningarbeiðnir virkar"</string>
<string name="accessibility_clear_all" msgid="5235938559247164925">"Hreinsa allar tilkynningar."</string>
- <!-- no translation found for notification_group_overflow_indicator (1863231301642314183) -->
- <skip />
+ <string name="notification_group_overflow_indicator" msgid="1863231301642314183">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string>
<string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"Tilkynningastillingar"</string>
<string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"Stillingar fyrir <xliff:g id="APP_NAME">%s</xliff:g>"</string>
<string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Skjárinn snýst sjálfkrafa."</string>
@@ -310,8 +311,7 @@
<string name="recents_search_bar_label" msgid="8074997400187836677">"leita"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"Ekki var hægt að ræsa <xliff:g id="APP">%s</xliff:g>."</string>
<string name="recents_launch_disabled_message" msgid="1624523193008871793">"Slökkt er á <xliff:g id="APP">%s</xliff:g> í öruggri stillingu."</string>
- <string name="recents_history_button_label" msgid="5153358867807604821">"Ferill"</string>
- <string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Hreinsa"</string>
+ <string name="recents_stack_action_button_label" msgid="6593727103310426253">"Hreinsa allt"</string>
<string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"Þetta forrit styður ekki marga glugga"</string>
<string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"Forritið styður ekki marga glugga"</string>
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Lárétt skipting"</string>
@@ -480,8 +480,7 @@
<string name="notification_importance_max" msgid="5806278962376556491">"Sýna efst á tilkynningalistanum, birta á skjánum og leyfa hljóð"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Fleiri stillingar"</string>
<string name="notification_done" msgid="5279426047273930175">"Lokið"</string>
- <!-- no translation found for notification_gear_accessibility (94429150213089611) -->
- <skip />
+ <string name="notification_gear_accessibility" msgid="94429150213089611">"Tilkynningastýringar <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="color_and_appearance" msgid="1254323855964993144">"Litur og útlit"</string>
<string name="night_mode" msgid="3540405868248625488">"Næturstilling"</string>
<string name="calibrate_display" msgid="5974642573432039217">"Kvarða skjáinn"</string>
@@ -501,10 +500,48 @@
<string name="battery_detail_charging_summary" msgid="1279095653533044008">"Ekki er hægt að nota rafhlöðusparnað meðan á hleðslu stendur"</string>
<string name="battery_detail_switch_title" msgid="6285872470260795421">"Rafhlöðusparnaður"</string>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"Dregur úr afköstum og bakgrunnsgögnum"</string>
+ <string name="keyboard_key_button_template" msgid="6230056639734377300">"Hnappur <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="keyboard_key_home" msgid="2243500072071305073">"Home"</string>
+ <string name="keyboard_key_back" msgid="2337450286042721351">"Til baka"</string>
+ <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"Upp"</string>
+ <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"Niður"</string>
+ <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"Vinstri"</string>
+ <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"Hægri"</string>
+ <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"Miðja"</string>
+ <string name="keyboard_key_tab" msgid="3871485650463164476">"Tab"</string>
+ <string name="keyboard_key_space" msgid="2499861316311153293">"Bilslá"</string>
+ <string name="keyboard_key_enter" msgid="5739632123216118137">"Enter"</string>
+ <string name="keyboard_key_backspace" msgid="1559580097512385854">"Bakklykill"</string>
+ <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"Spila/gera hlé"</string>
+ <string name="keyboard_key_media_stop" msgid="2859963958595908962">"Stöðva"</string>
+ <string name="keyboard_key_media_next" msgid="1894394911630345607">"Áfram"</string>
+ <string name="keyboard_key_media_previous" msgid="4256072387192967261">"Fyrri"</string>
+ <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"Spóla til baka"</string>
+ <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"Spóla áfram"</string>
+ <string name="keyboard_key_page_up" msgid="5654098530106845603">"Page Up"</string>
+ <string name="keyboard_key_page_down" msgid="8720502083731906136">"Page Down"</string>
+ <string name="keyboard_key_forward_del" msgid="1391451334716490176">"Delete"</string>
+ <string name="keyboard_key_move_home" msgid="2765693292069487486">"Home"</string>
+ <string name="keyboard_key_move_end" msgid="5901174332047975247">"End"</string>
+ <string name="keyboard_key_insert" msgid="8530501581636082614">"Insert"</string>
+ <string name="keyboard_key_num_lock" msgid="5052537581246772117">"Num Lock"</string>
+ <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"Tölulykill <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"Kerfi"</string>
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Heim"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Nýlegt"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Til baka"</string>
+ <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Tilkynningar"</string>
+ <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"Flýtilyklar"</string>
+ <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"Skipta um innsláttaraðferð"</string>
+ <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"Forrit"</string>
+ <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"Aðstoð"</string>
+ <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"Vafri"</string>
+ <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"Tengiliðir"</string>
+ <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"Tölvupóstur"</string>
+ <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"Spjall"</string>
+ <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"Tónlist"</string>
+ <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+ <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"Dagatal"</string>
<string name="tuner_full_zen_title" msgid="4540823317772234308">"Sýna með hljóðstyrksstillingum"</string>
<string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Ónáðið ekki"</string>
<string name="volume_dnd_silent" msgid="4363882330723050727">"Flýtihnappar fyrir hljóðstyrk"</string>
@@ -559,4 +596,14 @@
<string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Færa upp"</string>
<string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Færa til vinstri"</string>
<string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Færa til hægri"</string>
+ <string name="forced_resizable_info_text" msgid="7591061837558867999">"Hugsanlegt er að forritið virki ekki í mörgum gluggum"</string>
+ <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"Staða <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>. Ýttu tvisvar til að breyta."</string>
+ <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. Ýttu tvisvar til að bæta við."</string>
+ <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"Staða <xliff:g id="POSITION">%1$d</xliff:g>. Ýttu tvisvar til að velja."</string>
+ <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"Færa <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"Fjarlægja <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="TILE_NAME">%1$s</xliff:g> er bætt við í stöðu <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+ <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"<xliff:g id="TILE_NAME">%1$s</xliff:g> var fjarlægð"</string>
+ <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="TILE_NAME">%1$s</xliff:g> færð í stöðu <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+ <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Flýtistillingaritill."</string>
</resources>
diff --git a/packages/SystemUI/res/values-is-rIS/strings_tv.xml b/packages/SystemUI/res/values-is-rIS/strings_tv.xml
index 053beaf..09c67ec 100644
--- a/packages/SystemUI/res/values-is-rIS/strings_tv.xml
+++ b/packages/SystemUI/res/values-is-rIS/strings_tv.xml
@@ -26,6 +26,5 @@
<string name="pip_hold_home" msgid="340086535668778109">"Haltu "<b>"HOME"</b>"-hnappinum inni til að stjórna innfelldri mynd"</string>
<string name="pip_onboarding_description" msgid="2882896641362814195">"Haltu „Home“-hnappinum inni til að stjórna innfelldri mynd"</string>
<string name="pip_onboarding_button" msgid="3957426748484904611">"Ég skil"</string>
- <!-- no translation found for recents_tv_dismiss (3555093879593377731) -->
- <skip />
+ <string name="recents_tv_dismiss" msgid="3555093879593377731">"Hunsa"</string>
</resources>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index 5ccc39c..4a8ba99 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -168,6 +168,8 @@
<string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Elimina <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> eliminata."</string>
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Tutte le applicazioni recenti sono state rimosse."</string>
+ <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+ <skip />
<string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Avvio di <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
<string name="accessibility_notification_dismissed" msgid="854211387186306927">"Notifica eliminata."</string>
@@ -236,8 +238,7 @@
<string name="gps_notification_found_text" msgid="4619274244146446464">"Posizione stabilita dal GPS"</string>
<string name="accessibility_location_active" msgid="2427290146138169014">"Richieste di accesso alla posizione attive"</string>
<string name="accessibility_clear_all" msgid="5235938559247164925">"Cancella tutte le notifiche."</string>
- <!-- no translation found for notification_group_overflow_indicator (1863231301642314183) -->
- <skip />
+ <string name="notification_group_overflow_indicator" msgid="1863231301642314183">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string>
<string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"Impostazioni di notifica"</string>
<string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"Impostazioni di <xliff:g id="APP_NAME">%s</xliff:g>"</string>
<string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Lo schermo ruoterà automaticamente."</string>
@@ -310,8 +311,7 @@
<string name="recents_search_bar_label" msgid="8074997400187836677">"cerca"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"Impossibile avviare <xliff:g id="APP">%s</xliff:g>."</string>
<string name="recents_launch_disabled_message" msgid="1624523193008871793">"L\'app <xliff:g id="APP">%s</xliff:g> è stata disattivata in modalità provvisoria."</string>
- <string name="recents_history_button_label" msgid="5153358867807604821">"Cronologia"</string>
- <string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Cancella"</string>
+ <string name="recents_stack_action_button_label" msgid="6593727103310426253">"Cancella tutto"</string>
<string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"Questa app non supporta la modalità multi-finestra"</string>
<string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"L\'app non supporta la modalità multi-finestra"</string>
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Divisione in orizzontale"</string>
@@ -480,8 +480,7 @@
<string name="notification_importance_max" msgid="5806278962376556491">"Mostra in cima all\'elenco delle notifiche, visualizza sullo schermo e attiva l\'audio"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Altre impostazioni"</string>
<string name="notification_done" msgid="5279426047273930175">"Fine"</string>
- <!-- no translation found for notification_gear_accessibility (94429150213089611) -->
- <skip />
+ <string name="notification_gear_accessibility" msgid="94429150213089611">"Controlli di notifica per <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="color_and_appearance" msgid="1254323855964993144">"Colore e aspetto"</string>
<string name="night_mode" msgid="3540405868248625488">"Modalità notturna"</string>
<string name="calibrate_display" msgid="5974642573432039217">"Calibra display"</string>
@@ -501,10 +500,48 @@
<string name="battery_detail_charging_summary" msgid="1279095653533044008">"Risparmio energetico non disponibile durante la ricarica"</string>
<string name="battery_detail_switch_title" msgid="6285872470260795421">"Risparmio energetico"</string>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"Riduce le prestazioni e i dati in background"</string>
+ <string name="keyboard_key_button_template" msgid="6230056639734377300">"Pulsante <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="keyboard_key_home" msgid="2243500072071305073">"Home page"</string>
+ <string name="keyboard_key_back" msgid="2337450286042721351">"Indietro"</string>
+ <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"Su"</string>
+ <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"Giù"</string>
+ <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"Sinistra"</string>
+ <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"Destra"</string>
+ <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"Al centro"</string>
+ <string name="keyboard_key_tab" msgid="3871485650463164476">"Scheda"</string>
+ <string name="keyboard_key_space" msgid="2499861316311153293">"Spazio"</string>
+ <string name="keyboard_key_enter" msgid="5739632123216118137">"Invio"</string>
+ <string name="keyboard_key_backspace" msgid="1559580097512385854">"Backspace"</string>
+ <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"Play/Pausa"</string>
+ <string name="keyboard_key_media_stop" msgid="2859963958595908962">"Interrompi"</string>
+ <string name="keyboard_key_media_next" msgid="1894394911630345607">"Avanti"</string>
+ <string name="keyboard_key_media_previous" msgid="4256072387192967261">"Precedente"</string>
+ <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"Riavvolgi"</string>
+ <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"Avanza velocemente"</string>
+ <string name="keyboard_key_page_up" msgid="5654098530106845603">"Pagina su"</string>
+ <string name="keyboard_key_page_down" msgid="8720502083731906136">"Pagina giù"</string>
+ <string name="keyboard_key_forward_del" msgid="1391451334716490176">"Elimina"</string>
+ <string name="keyboard_key_move_home" msgid="2765693292069487486">"Home page"</string>
+ <string name="keyboard_key_move_end" msgid="5901174332047975247">"Fine"</string>
+ <string name="keyboard_key_insert" msgid="8530501581636082614">"INS"</string>
+ <string name="keyboard_key_num_lock" msgid="5052537581246772117">"Bloc Num"</string>
+ <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"Tastierino numerico <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"Sistema"</string>
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Home"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Recenti"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Indietro"</string>
+ <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Notifiche"</string>
+ <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"Scorciatoie da tastiera"</string>
+ <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"Cambia metodo di immissione"</string>
+ <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"Applicazioni"</string>
+ <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"Assistenza"</string>
+ <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"Browser"</string>
+ <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"Contatti"</string>
+ <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"Email"</string>
+ <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"Chat"</string>
+ <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"Musica"</string>
+ <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+ <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"Calendario"</string>
<string name="tuner_full_zen_title" msgid="4540823317772234308">"Mostra con controlli volume"</string>
<string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Non disturbare"</string>
<string name="volume_dnd_silent" msgid="4363882330723050727">"Pulsanti del volume come scorciatoia"</string>
@@ -559,4 +596,14 @@
<string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Sposta su"</string>
<string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Sposta a sinistra"</string>
<string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Sposta a destra"</string>
+ <string name="forced_resizable_info_text" msgid="7591061837558867999">"L\'app potrebbe non funzionare con la modalità multi-finestra"</string>
+ <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"Posizione <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>. Tocca due volte per modificare."</string>
+ <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. Tocca due volte per aggiungere."</string>
+ <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"Posizione <xliff:g id="POSITION">%1$d</xliff:g>. Tocca due volte per selezionare."</string>
+ <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"Sposta <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"Rimuovi <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"Il riquadro <xliff:g id="TILE_NAME">%1$s</xliff:g> è stato aggiunto alla posizione <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+ <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"Il riquadro <xliff:g id="TILE_NAME">%1$s</xliff:g> è stato rimosso"</string>
+ <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"Il riquadro <xliff:g id="TILE_NAME">%1$s</xliff:g> è stato spostato nella posizione <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+ <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Editor di impostazioni rapide."</string>
</resources>
diff --git a/packages/SystemUI/res/values-it/strings_tv.xml b/packages/SystemUI/res/values-it/strings_tv.xml
index 5001b95..4ea019b 100644
--- a/packages/SystemUI/res/values-it/strings_tv.xml
+++ b/packages/SystemUI/res/values-it/strings_tv.xml
@@ -26,6 +26,5 @@
<string name="pip_hold_home" msgid="340086535668778109">"Tieni premuto "<b>"HOME"</b>" per controllare PIP"</string>
<string name="pip_onboarding_description" msgid="2882896641362814195">"Tieni premuto il pulsante HOME per controllare PIP"</string>
<string name="pip_onboarding_button" msgid="3957426748484904611">"OK"</string>
- <!-- no translation found for recents_tv_dismiss (3555093879593377731) -->
- <skip />
+ <string name="recents_tv_dismiss" msgid="3555093879593377731">"Ignora"</string>
</resources>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index 52c83ba..d41d50d 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -170,6 +170,8 @@
<string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"סגור את <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> נדחה."</string>
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"כל האפליקציות האחרונות נסגרו."</string>
+ <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+ <skip />
<string name="accessibility_recents_item_launched" msgid="7616039892382525203">"מפעיל את <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
<string name="accessibility_notification_dismissed" msgid="854211387186306927">"הודעה נדחתה."</string>
@@ -238,8 +240,7 @@
<string name="gps_notification_found_text" msgid="4619274244146446464">"מיקום מוגדר על ידי GPS"</string>
<string name="accessibility_location_active" msgid="2427290146138169014">"בקשות מיקום פעילות"</string>
<string name="accessibility_clear_all" msgid="5235938559247164925">"נקה את כל ההתראות."</string>
- <!-- no translation found for notification_group_overflow_indicator (1863231301642314183) -->
- <skip />
+ <string name="notification_group_overflow_indicator" msgid="1863231301642314183">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string>
<string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"הגדרות עבור הודעות"</string>
<string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"הגדרות <xliff:g id="APP_NAME">%s</xliff:g>"</string>
<string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"המסך יסתובב באופן אוטומטי."</string>
@@ -312,8 +313,7 @@
<string name="recents_search_bar_label" msgid="8074997400187836677">"חפש"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"לא ניתן היה להפעיל את <xliff:g id="APP">%s</xliff:g>."</string>
<string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g> מושבת במצב בטוח."</string>
- <string name="recents_history_button_label" msgid="5153358867807604821">"היסטוריה"</string>
- <string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"נקה"</string>
+ <string name="recents_stack_action_button_label" msgid="6593727103310426253">"נקה הכל"</string>
<string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"אפליקציה זו אינה תומכת בריבוי חלונות"</string>
<string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"האפליקציה אינה תומכת בריבוי חלונות"</string>
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"פיצול אופקי"</string>
@@ -482,8 +482,7 @@
<string name="notification_importance_max" msgid="5806278962376556491">"הצג בראש רשימת ההודעות, הצג לרגע על גבי המסך ואשר השמעת צליל"</string>
<string name="notification_more_settings" msgid="816306283396553571">"הגדרות נוספות"</string>
<string name="notification_done" msgid="5279426047273930175">"סיום"</string>
- <!-- no translation found for notification_gear_accessibility (94429150213089611) -->
- <skip />
+ <string name="notification_gear_accessibility" msgid="94429150213089611">"<xliff:g id="APP_NAME">%1$s</xliff:g> פקדי הודעות"</string>
<string name="color_and_appearance" msgid="1254323855964993144">"צבע ומראה"</string>
<string name="night_mode" msgid="3540405868248625488">"מצב לילה"</string>
<string name="calibrate_display" msgid="5974642573432039217">"כיול תצוגה"</string>
@@ -503,10 +502,48 @@
<string name="battery_detail_charging_summary" msgid="1279095653533044008">"תכונת החיסכון בסוללה אינה זמינה בעת טעינת המכשיר"</string>
<string name="battery_detail_switch_title" msgid="6285872470260795421">"חיסכון בסוללה"</string>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"מפחית את רמת הביצועים ואת נתוני הרקע"</string>
+ <string name="keyboard_key_button_template" msgid="6230056639734377300">"לחצן <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="keyboard_key_home" msgid="2243500072071305073">"דף הבית"</string>
+ <string name="keyboard_key_back" msgid="2337450286042721351">"הקודם"</string>
+ <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"למעלה"</string>
+ <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"למטה"</string>
+ <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"שמאלה"</string>
+ <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"ימינה"</string>
+ <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"מרכז"</string>
+ <string name="keyboard_key_tab" msgid="3871485650463164476">"כרטיסייה"</string>
+ <string name="keyboard_key_space" msgid="2499861316311153293">"רווח"</string>
+ <string name="keyboard_key_enter" msgid="5739632123216118137">"Enter"</string>
+ <string name="keyboard_key_backspace" msgid="1559580097512385854">"BACKSPACE"</string>
+ <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"הפעל/השהה"</string>
+ <string name="keyboard_key_media_stop" msgid="2859963958595908962">"עצור"</string>
+ <string name="keyboard_key_media_next" msgid="1894394911630345607">"הבא"</string>
+ <string name="keyboard_key_media_previous" msgid="4256072387192967261">"הקודם"</string>
+ <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"הרץ אחורה"</string>
+ <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"הרץ קדימה"</string>
+ <string name="keyboard_key_page_up" msgid="5654098530106845603">"דפדוף למעלה"</string>
+ <string name="keyboard_key_page_down" msgid="8720502083731906136">"דפדוף למטה"</string>
+ <string name="keyboard_key_forward_del" msgid="1391451334716490176">"מחיקה"</string>
+ <string name="keyboard_key_move_home" msgid="2765693292069487486">"דף הבית"</string>
+ <string name="keyboard_key_move_end" msgid="5901174332047975247">"סיום"</string>
+ <string name="keyboard_key_insert" msgid="8530501581636082614">"הזן"</string>
+ <string name="keyboard_key_num_lock" msgid="5052537581246772117">"מקש Num Lock"</string>
+ <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"מקלדת נומרית <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"מערכת"</string>
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"דף הבית"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"אחרונים"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"הקודם"</string>
+ <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"הודעות"</string>
+ <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"מקשי קיצור במקלדת"</string>
+ <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"החלפת שיטת קלט"</string>
+ <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"אפליקציות"</string>
+ <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"מסייע"</string>
+ <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"דפדפן"</string>
+ <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"אנשי קשר"</string>
+ <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"אימייל"</string>
+ <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"שליחת הודעות מיידיות"</string>
+ <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"מוזיקה"</string>
+ <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+ <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"יומן"</string>
<string name="tuner_full_zen_title" msgid="4540823317772234308">"הצג עם פקדי עוצמת הקול"</string>
<string name="volume_and_do_not_disturb" msgid="3373784330208603030">"נא לא להפריע"</string>
<string name="volume_dnd_silent" msgid="4363882330723050727">"מקש קיצור ללחצני עוצמת קול"</string>
@@ -542,8 +579,7 @@
<string name="select_keycode" msgid="7413765103381924584">"בחירת לחצן מקלדת"</string>
<string name="preview" msgid="9077832302472282938">"תצוגה מקדימה"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"גרור כדי להוסיף משבצות"</string>
- <!-- no translation found for drag_to_remove_tiles (3361212377437088062) -->
- <skip />
+ <string name="drag_to_remove_tiles" msgid="3361212377437088062">"גרור לכאן כדי להסיר"</string>
<string name="qs_edit" msgid="2232596095725105230">"ערוך"</string>
<string name="tuner_time" msgid="6572217313285536011">"שעה"</string>
<string-array name="clock_options">
@@ -562,4 +598,14 @@
<string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"הזז למעלה"</string>
<string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"הזז שמאלה"</string>
<string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"הזז ימינה"</string>
+ <string name="forced_resizable_info_text" msgid="7591061837558867999">"ייתכן שהאפליקציה לא תפעל עם ריבוי חלונות"</string>
+ <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"מיקום <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>. הקש פעמיים כדי לערוך."</string>
+ <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. הקש פעמיים כדי להוסיף."</string>
+ <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"מיקום <xliff:g id="POSITION">%1$d</xliff:g>. הקש פעמיים כדי לבחור."</string>
+ <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"הזזת <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"הסרת <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="TILE_NAME">%1$s</xliff:g> התווסף למיקום <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+ <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"<xliff:g id="TILE_NAME">%1$s</xliff:g> הוסר"</string>
+ <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="TILE_NAME">%1$s</xliff:g> הועבר למיקום <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+ <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"עורך הגדרות מהירות."</string>
</resources>
diff --git a/packages/SystemUI/res/values-iw/strings_tv.xml b/packages/SystemUI/res/values-iw/strings_tv.xml
index f4d4094..9130d53 100644
--- a/packages/SystemUI/res/values-iw/strings_tv.xml
+++ b/packages/SystemUI/res/values-iw/strings_tv.xml
@@ -26,6 +26,5 @@
<string name="pip_hold_home" msgid="340086535668778109">"לחץ לחיצה ארוכה על "<b>"דף הבית"</b>" כדי לשלוט ב-PIP"</string>
<string name="pip_onboarding_description" msgid="2882896641362814195">"לחץ לחיצה ממושכת על לחצן דף הבית כדי לשלוט ב-PIP"</string>
<string name="pip_onboarding_button" msgid="3957426748484904611">"הבנתי"</string>
- <!-- no translation found for recents_tv_dismiss (3555093879593377731) -->
- <skip />
+ <string name="recents_tv_dismiss" msgid="3555093879593377731">"דחה"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index f7aacee..83a9888 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -168,6 +168,8 @@
<string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"<xliff:g id="APP">%s</xliff:g>を削除します。"</string>
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g>は削除されました。"</string>
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"最近のアプリケーションをすべて消去しました。"</string>
+ <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+ <skip />
<string name="accessibility_recents_item_launched" msgid="7616039892382525203">"<xliff:g id="APP">%s</xliff:g>を開始しています。"</string>
<string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
<string name="accessibility_notification_dismissed" msgid="854211387186306927">"通知が削除されました。"</string>
@@ -236,8 +238,7 @@
<string name="gps_notification_found_text" msgid="4619274244146446464">"GPSにより現在地が設定されました"</string>
<string name="accessibility_location_active" msgid="2427290146138169014">"現在地リクエストがアクティブ"</string>
<string name="accessibility_clear_all" msgid="5235938559247164925">"通知をすべて消去。"</string>
- <!-- no translation found for notification_group_overflow_indicator (1863231301642314183) -->
- <skip />
+ <string name="notification_group_overflow_indicator" msgid="1863231301642314183">"他 <xliff:g id="NUMBER">%s</xliff:g> 件"</string>
<string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"通知設定"</string>
<string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"<xliff:g id="APP_NAME">%s</xliff:g>の設定"</string>
<string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"画面は自動的に回転します。"</string>
@@ -310,8 +311,7 @@
<string name="recents_search_bar_label" msgid="8074997400187836677">"検索"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g>を開始できません。"</string>
<string name="recents_launch_disabled_message" msgid="1624523193008871793">"「<xliff:g id="APP">%s</xliff:g>」はセーフモードでは無効になります。"</string>
- <string name="recents_history_button_label" msgid="5153358867807604821">"履歴"</string>
- <string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"消去"</string>
+ <string name="recents_stack_action_button_label" msgid="6593727103310426253">"すべて消去"</string>
<string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"このアプリはマルチウィンドウに対応していません"</string>
<string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"アプリはマルチウィンドウに対応していません"</string>
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"横に分割"</string>
@@ -480,8 +480,7 @@
<string name="notification_importance_max" msgid="5806278962376556491">"通知リストの先頭に表示し、画面に数秒間表示し、音声でも知らせる"</string>
<string name="notification_more_settings" msgid="816306283396553571">"詳細設定"</string>
<string name="notification_done" msgid="5279426047273930175">"完了"</string>
- <!-- no translation found for notification_gear_accessibility (94429150213089611) -->
- <skip />
+ <string name="notification_gear_accessibility" msgid="94429150213089611">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」の通知の管理"</string>
<string name="color_and_appearance" msgid="1254323855964993144">"色と表示"</string>
<string name="night_mode" msgid="3540405868248625488">"夜間モード"</string>
<string name="calibrate_display" msgid="5974642573432039217">"表示の調整"</string>
@@ -501,10 +500,48 @@
<string name="battery_detail_charging_summary" msgid="1279095653533044008">"充電中はバッテリー セーバーは利用できません"</string>
<string name="battery_detail_switch_title" msgid="6285872470260795421">"バッテリー セーバー"</string>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"パフォーマンスとバックグラウンド データを制限します"</string>
+ <string name="keyboard_key_button_template" msgid="6230056639734377300">"<xliff:g id="NAME">%1$s</xliff:g> ボタン"</string>
+ <string name="keyboard_key_home" msgid="2243500072071305073">"Home"</string>
+ <string name="keyboard_key_back" msgid="2337450286042721351">"戻る"</string>
+ <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"上"</string>
+ <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"下"</string>
+ <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"左"</string>
+ <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"右"</string>
+ <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"中央"</string>
+ <string name="keyboard_key_tab" msgid="3871485650463164476">"Tab"</string>
+ <string name="keyboard_key_space" msgid="2499861316311153293">"Space"</string>
+ <string name="keyboard_key_enter" msgid="5739632123216118137">"Enter"</string>
+ <string name="keyboard_key_backspace" msgid="1559580097512385854">"Backspace"</string>
+ <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"再生 / 一時停止"</string>
+ <string name="keyboard_key_media_stop" msgid="2859963958595908962">"停止"</string>
+ <string name="keyboard_key_media_next" msgid="1894394911630345607">"次へ"</string>
+ <string name="keyboard_key_media_previous" msgid="4256072387192967261">"前へ"</string>
+ <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"巻き戻し"</string>
+ <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"早送り"</string>
+ <string name="keyboard_key_page_up" msgid="5654098530106845603">"PageUp"</string>
+ <string name="keyboard_key_page_down" msgid="8720502083731906136">"PageDown"</string>
+ <string name="keyboard_key_forward_del" msgid="1391451334716490176">"Delete"</string>
+ <string name="keyboard_key_move_home" msgid="2765693292069487486">"Home"</string>
+ <string name="keyboard_key_move_end" msgid="5901174332047975247">"End"</string>
+ <string name="keyboard_key_insert" msgid="8530501581636082614">"Insert"</string>
+ <string name="keyboard_key_num_lock" msgid="5052537581246772117">"NumLock"</string>
+ <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"テンキーの <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"システム"</string>
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"ホーム"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"最近"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"戻る"</string>
+ <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"通知"</string>
+ <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"キーボード ショートカット"</string>
+ <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"入力方法の切り替え"</string>
+ <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"アプリ"</string>
+ <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"アシスト"</string>
+ <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"ブラウザ"</string>
+ <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"連絡先"</string>
+ <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"メール"</string>
+ <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"IM"</string>
+ <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"音楽"</string>
+ <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+ <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"カレンダー"</string>
<string name="tuner_full_zen_title" msgid="4540823317772234308">"音量調節を表示"</string>
<string name="volume_and_do_not_disturb" msgid="3373784330208603030">"通知の非表示"</string>
<string name="volume_dnd_silent" msgid="4363882330723050727">"音量ボタンのショートカット"</string>
@@ -559,4 +596,14 @@
<string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"上に移動"</string>
<string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"左に移動"</string>
<string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"右に移動"</string>
+ <string name="forced_resizable_info_text" msgid="7591061837558867999">"アプリはマルチウィンドウでは動作しないことがあります"</string>
+ <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"ポジション <xliff:g id="POSITION">%1$d</xliff:g> の <xliff:g id="TILE_NAME">%2$s</xliff:g> を編集するにはダブルタップします。"</string>
+ <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g> を追加するにはダブルタップします。"</string>
+ <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"ポジション <xliff:g id="POSITION">%1$d</xliff:g> に配置します。選択するにはダブルタップします。"</string>
+ <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"<xliff:g id="TILE_NAME">%1$s</xliff:g> を移動します"</string>
+ <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"<xliff:g id="TILE_NAME">%1$s</xliff:g> を削除します"</string>
+ <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="TILE_NAME">%1$s</xliff:g> をポジション <xliff:g id="POSITION">%2$d</xliff:g> に追加しました"</string>
+ <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"<xliff:g id="TILE_NAME">%1$s</xliff:g> を削除しました"</string>
+ <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="TILE_NAME">%1$s</xliff:g> をポジション <xliff:g id="POSITION">%2$d</xliff:g> に移動しました"</string>
+ <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"クイック設定エディタ"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ja/strings_tv.xml b/packages/SystemUI/res/values-ja/strings_tv.xml
index a4c49b3..0f0032f 100644
--- a/packages/SystemUI/res/values-ja/strings_tv.xml
+++ b/packages/SystemUI/res/values-ja/strings_tv.xml
@@ -26,6 +26,5 @@
<string name="pip_hold_home" msgid="340086535668778109">"PIP を管理するには ["<b>"ホーム"</b>"] を押し続けます"</string>
<string name="pip_onboarding_description" msgid="2882896641362814195">"PIP を管理するには [ホーム] ボタンを押し続けます"</string>
<string name="pip_onboarding_button" msgid="3957426748484904611">"閉じる"</string>
- <!-- no translation found for recents_tv_dismiss (3555093879593377731) -->
- <skip />
+ <string name="recents_tv_dismiss" msgid="3555093879593377731">"閉じる"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ka-rGE/strings.xml b/packages/SystemUI/res/values-ka-rGE/strings.xml
index 9730323..5008fe0 100644
--- a/packages/SystemUI/res/values-ka-rGE/strings.xml
+++ b/packages/SystemUI/res/values-ka-rGE/strings.xml
@@ -168,6 +168,8 @@
<string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"<xliff:g id="APP">%s</xliff:g>-ის უგულებელყოფა."</string>
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> ამოშლილია სიიდან."</string>
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"ყველა ბოლო აპლიკაცია გაუქმდა."</string>
+ <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+ <skip />
<string name="accessibility_recents_item_launched" msgid="7616039892382525203">"<xliff:g id="APP">%s</xliff:g> იწყება."</string>
<string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
<string name="accessibility_notification_dismissed" msgid="854211387186306927">"შეტყობინება წაიშალა."</string>
@@ -236,8 +238,7 @@
<string name="gps_notification_found_text" msgid="4619274244146446464">"GPS-ით დადგენილი მდებარეობა"</string>
<string name="accessibility_location_active" msgid="2427290146138169014">"მდებარეობის მოთხოვნები აქტიურია"</string>
<string name="accessibility_clear_all" msgid="5235938559247164925">"ყველა შეტყობინების წაშლა"</string>
- <!-- no translation found for notification_group_overflow_indicator (1863231301642314183) -->
- <skip />
+ <string name="notification_group_overflow_indicator" msgid="1863231301642314183">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string>
<string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"შეტყობინების პარამეტრები"</string>
<string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"<xliff:g id="APP_NAME">%s</xliff:g> პარამეტრები"</string>
<string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"ეკრანი შეტრიალდება ავტომატურად."</string>
@@ -310,8 +311,7 @@
<string name="recents_search_bar_label" msgid="8074997400187836677">"ძიება"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g>-ის გამოძახება ვერ მოხერხდა."</string>
<string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g> გათიშულია უსაფრთხო რეჟიმში."</string>
- <string name="recents_history_button_label" msgid="5153358867807604821">"ისტორია"</string>
- <string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"გასუფთავება"</string>
+ <string name="recents_stack_action_button_label" msgid="6593727103310426253">"ყველას გასუფთავება"</string>
<string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"მრავალი ფანჯრის რეჟიმი არ არის მხარდაჭერილი ამ აპის მიერ"</string>
<string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"მრავალი ფანჯრის რეჟიმი არ არის მხარდაჭერილი აპის მიერ"</string>
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"ჰორიზონტალური გაყოფა"</string>
@@ -480,8 +480,7 @@
<string name="notification_importance_max" msgid="5806278962376556491">"შეტყობინებების სიის თავში ჩვენება, პირდაპირ ეკრანზე გამოჩენა და ხმის დაშვება"</string>
<string name="notification_more_settings" msgid="816306283396553571">"დამატებითი პარამეტრები"</string>
<string name="notification_done" msgid="5279426047273930175">"მზადაა"</string>
- <!-- no translation found for notification_gear_accessibility (94429150213089611) -->
- <skip />
+ <string name="notification_gear_accessibility" msgid="94429150213089611">"<xliff:g id="APP_NAME">%1$s</xliff:g> შეტყობინებების მართვის საშუალებები"</string>
<string name="color_and_appearance" msgid="1254323855964993144">"ფერი და იერსახე"</string>
<string name="night_mode" msgid="3540405868248625488">"ღამის რეჟიმი"</string>
<string name="calibrate_display" msgid="5974642573432039217">"ეკრანის კალიბრაცია"</string>
@@ -501,10 +500,48 @@
<string name="battery_detail_charging_summary" msgid="1279095653533044008">"ბატარეის დამზოგი დატენვისას მიწვდომელია"</string>
<string name="battery_detail_switch_title" msgid="6285872470260795421">"ბატარეის დამზოგი"</string>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"ამცირებს წარმადობას და ფონურ მონაცემებს"</string>
+ <string name="keyboard_key_button_template" msgid="6230056639734377300">"ღილაკი „<xliff:g id="NAME">%1$s</xliff:g>“"</string>
+ <string name="keyboard_key_home" msgid="2243500072071305073">"Home"</string>
+ <string name="keyboard_key_back" msgid="2337450286042721351">"უკან"</string>
+ <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"ზემოთ"</string>
+ <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"ქვემოთ"</string>
+ <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"მარცხნივ"</string>
+ <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"მარჯვნივ"</string>
+ <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"ცენტრში"</string>
+ <string name="keyboard_key_tab" msgid="3871485650463164476">"Tab"</string>
+ <string name="keyboard_key_space" msgid="2499861316311153293">"შორისი"</string>
+ <string name="keyboard_key_enter" msgid="5739632123216118137">"Enter"</string>
+ <string name="keyboard_key_backspace" msgid="1559580097512385854">"Backspace"</string>
+ <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"დაკვრა/პაუზა"</string>
+ <string name="keyboard_key_media_stop" msgid="2859963958595908962">"შეწყვეტა"</string>
+ <string name="keyboard_key_media_next" msgid="1894394911630345607">"შემდეგი"</string>
+ <string name="keyboard_key_media_previous" msgid="4256072387192967261">"წინა"</string>
+ <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"უკან გადახვევა"</string>
+ <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"წინ გადახვევა"</string>
+ <string name="keyboard_key_page_up" msgid="5654098530106845603">"Page Up"</string>
+ <string name="keyboard_key_page_down" msgid="8720502083731906136">"Page Down"</string>
+ <string name="keyboard_key_forward_del" msgid="1391451334716490176">"Delete"</string>
+ <string name="keyboard_key_move_home" msgid="2765693292069487486">"Home"</string>
+ <string name="keyboard_key_move_end" msgid="5901174332047975247">"End"</string>
+ <string name="keyboard_key_insert" msgid="8530501581636082614">"Insert"</string>
+ <string name="keyboard_key_num_lock" msgid="5052537581246772117">"Num Lock"</string>
+ <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"რიცხვთა პანელი <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"სისტემა"</string>
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"მთავარი"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"ბოლოს გამოყენებული"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"უკან"</string>
+ <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"შეტყობინებები"</string>
+ <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"კლავიატურის მალსახმობები"</string>
+ <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"შეყვანის მეთოდის გადართვა"</string>
+ <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"აპლიკაციები"</string>
+ <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"დახმარება"</string>
+ <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"ბრაუზერი"</string>
+ <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"კონტაქტები"</string>
+ <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"ელფოსტა"</string>
+ <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"IM"</string>
+ <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"მუსიკა"</string>
+ <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+ <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"კალენდარი"</string>
<string name="tuner_full_zen_title" msgid="4540823317772234308">"ხმის მართვის საშუალებების ჩვენება"</string>
<string name="volume_and_do_not_disturb" msgid="3373784330208603030">"არ შემაწუხოთ"</string>
<string name="volume_dnd_silent" msgid="4363882330723050727">"ხმის ღილაკების მალსახმობი"</string>
@@ -540,8 +577,7 @@
<string name="select_keycode" msgid="7413765103381924584">"აირჩიეთ კლავიატურის ღილაკი"</string>
<string name="preview" msgid="9077832302472282938">"გადახედვა"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"ფილების დასამატებლად, გადაიტანეთ ჩავლებით"</string>
- <!-- no translation found for drag_to_remove_tiles (3361212377437088062) -->
- <skip />
+ <string name="drag_to_remove_tiles" msgid="3361212377437088062">"ამოსაშლელად, ჩავლებით გადმოიტანეთ აქ"</string>
<string name="qs_edit" msgid="2232596095725105230">"რედაქტირება"</string>
<string name="tuner_time" msgid="6572217313285536011">"დრო"</string>
<string-array name="clock_options">
@@ -560,4 +596,14 @@
<string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"ზემოთ გადატანა"</string>
<string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"მარცხნივ გადატანა"</string>
<string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"მარჯვნივ გადატანა"</string>
+ <string name="forced_resizable_info_text" msgid="7591061837558867999">"აპმა შეიძლება არ იმუშაოს მრავალი ფანჯრის რეჟიმში"</string>
+ <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"პოზიცია <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>. რედაქტირებისთვის, შეეხეთ ორმაგად."</string>
+ <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. დასამატებლად, შეეხეთ ორმაგად."</string>
+ <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"პოზიცია <xliff:g id="POSITION">%1$d</xliff:g>. ასარჩევად, შეეხეთ ორმაგად."</string>
+ <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"<xliff:g id="TILE_NAME">%1$s</xliff:g>-ის გადატანა"</string>
+ <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"<xliff:g id="TILE_NAME">%1$s</xliff:g>-ის წაშლა"</string>
+ <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="TILE_NAME">%1$s</xliff:g> დამატებულია პოზიციაზე <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+ <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"<xliff:g id="TILE_NAME">%1$s</xliff:g> ამოიშალა"</string>
+ <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="TILE_NAME">%1$s</xliff:g> გადატანილია პოზიციაზე <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+ <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"სწრაფი პარამეტრების რედაქტორი."</string>
</resources>
diff --git a/packages/SystemUI/res/values-ka-rGE/strings_tv.xml b/packages/SystemUI/res/values-ka-rGE/strings_tv.xml
index 3a556ae..7d615ba 100644
--- a/packages/SystemUI/res/values-ka-rGE/strings_tv.xml
+++ b/packages/SystemUI/res/values-ka-rGE/strings_tv.xml
@@ -26,6 +26,5 @@
<string name="pip_hold_home" msgid="340086535668778109">"PIP-ის სამართავად, გეჭიროთ "<b>"მთავარ ღილაკზე"</b></string>
<string name="pip_onboarding_description" msgid="2882896641362814195">"PIP-ის სამართავად, ხანგრძლივად დააჭირეთ მთავარ ღილაკს"</string>
<string name="pip_onboarding_button" msgid="3957426748484904611">"გასაგებია"</string>
- <!-- no translation found for recents_tv_dismiss (3555093879593377731) -->
- <skip />
+ <string name="recents_tv_dismiss" msgid="3555093879593377731">"დახურვა"</string>
</resources>
diff --git a/packages/SystemUI/res/values-kk-rKZ/strings.xml b/packages/SystemUI/res/values-kk-rKZ/strings.xml
index f6c1152..ff33f05 100644
--- a/packages/SystemUI/res/values-kk-rKZ/strings.xml
+++ b/packages/SystemUI/res/values-kk-rKZ/strings.xml
@@ -168,6 +168,8 @@
<string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"<xliff:g id="APP">%s</xliff:g> қолданбасынан бас тарту."</string>
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> алынып тасталған."</string>
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Барлық жақындағы қабылданбаған қолданбалар."</string>
+ <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+ <skip />
<string name="accessibility_recents_item_launched" msgid="7616039892382525203">"<xliff:g id="APP">%s</xliff:g> іске қосылуда."</string>
<string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
<string name="accessibility_notification_dismissed" msgid="854211387186306927">"Хабар алынып тасталды."</string>
@@ -236,8 +238,7 @@
<string name="gps_notification_found_text" msgid="4619274244146446464">"Орын GPS арқылы орнатылған"</string>
<string name="accessibility_location_active" msgid="2427290146138169014">"Орын өтініштері қосылған"</string>
<string name="accessibility_clear_all" msgid="5235938559247164925">"Барлық хабарларды жойыңыз."</string>
- <!-- no translation found for notification_group_overflow_indicator (1863231301642314183) -->
- <skip />
+ <string name="notification_group_overflow_indicator" msgid="1863231301642314183">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string>
<string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"Хабарландыру параметрлері"</string>
<string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"<xliff:g id="APP_NAME">%s</xliff:g> параметрлері"</string>
<string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Экран автоматты түрде бұрылады."</string>
@@ -310,8 +311,7 @@
<string name="recents_search_bar_label" msgid="8074997400187836677">"іздеу"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g> іске қосу мүмкін болмады."</string>
<string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g> қауіпсіз режимде өшіріледі."</string>
- <string name="recents_history_button_label" msgid="5153358867807604821">"Тарих"</string>
- <string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Тазалау"</string>
+ <string name="recents_stack_action_button_label" msgid="6593727103310426253">"Барлығын тазалау"</string>
<string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"Бұл қолданба көп терезені қолдамайды"</string>
<string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"Қолданба көп терезені қолдамайды"</string>
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Бөлінген көлденең"</string>
@@ -480,8 +480,7 @@
<string name="notification_importance_max" msgid="5806278962376556491">"Хабарландырулар тізімінің жоғарғы жағында көрсету, экранда көрсету және дыбысқа рұқсат ету"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Қосымша параметрлер"</string>
<string name="notification_done" msgid="5279426047273930175">"Дайын"</string>
- <!-- no translation found for notification_gear_accessibility (94429150213089611) -->
- <skip />
+ <string name="notification_gear_accessibility" msgid="94429150213089611">"<xliff:g id="APP_NAME">%1$s</xliff:g> хабарландыруларды басқару элементтері"</string>
<string name="color_and_appearance" msgid="1254323855964993144">"Түс және сыртқы түрі"</string>
<string name="night_mode" msgid="3540405868248625488">"Түнгі режим"</string>
<string name="calibrate_display" msgid="5974642573432039217">"Дисплейді калибрлеу"</string>
@@ -501,10 +500,48 @@
<string name="battery_detail_charging_summary" msgid="1279095653533044008">"Зарядтау кезінде Батарея үнемдегіш қол жетімді емес"</string>
<string name="battery_detail_switch_title" msgid="6285872470260795421">"Батарея үнемдегіш"</string>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"Өнімділікті және фондық деректерді азайтады"</string>
+ <string name="keyboard_key_button_template" msgid="6230056639734377300">"<xliff:g id="NAME">%1$s</xliff:g> түймесі"</string>
+ <string name="keyboard_key_home" msgid="2243500072071305073">"Home"</string>
+ <string name="keyboard_key_back" msgid="2337450286042721351">"Артқа"</string>
+ <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"Жоғары"</string>
+ <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"Төмен"</string>
+ <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"Сол"</string>
+ <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"Оң"</string>
+ <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"Орталық"</string>
+ <string name="keyboard_key_tab" msgid="3871485650463164476">"Tab"</string>
+ <string name="keyboard_key_space" msgid="2499861316311153293">"Бос орын"</string>
+ <string name="keyboard_key_enter" msgid="5739632123216118137">"Enter"</string>
+ <string name="keyboard_key_backspace" msgid="1559580097512385854">"Backspace"</string>
+ <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"Ойнату/кідірту"</string>
+ <string name="keyboard_key_media_stop" msgid="2859963958595908962">"Тоқтату"</string>
+ <string name="keyboard_key_media_next" msgid="1894394911630345607">"Келесі"</string>
+ <string name="keyboard_key_media_previous" msgid="4256072387192967261">"Алдыңғы"</string>
+ <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"Кері айналдыру"</string>
+ <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"Алға айналдыру"</string>
+ <string name="keyboard_key_page_up" msgid="5654098530106845603">"Page Up"</string>
+ <string name="keyboard_key_page_down" msgid="8720502083731906136">"Page Down"</string>
+ <string name="keyboard_key_forward_del" msgid="1391451334716490176">"Delete"</string>
+ <string name="keyboard_key_move_home" msgid="2765693292069487486">"Home"</string>
+ <string name="keyboard_key_move_end" msgid="5901174332047975247">"End"</string>
+ <string name="keyboard_key_insert" msgid="8530501581636082614">"Insert"</string>
+ <string name="keyboard_key_num_lock" msgid="5052537581246772117">"Num Lock"</string>
+ <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"Сандық пернетақта <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"Жүйе"</string>
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Негізгі бет"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Жақындағылар"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Артқа"</string>
+ <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Хабарландырулар"</string>
+ <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"Пернелер тіркесімдері"</string>
+ <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"Енгізу әдісін ауыстыру"</string>
+ <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"Қолданбалар"</string>
+ <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"Көмекші"</string>
+ <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"Браузер"</string>
+ <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"Контактілер"</string>
+ <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"Электрондық пошта"</string>
+ <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"IM"</string>
+ <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"Mузыка"</string>
+ <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+ <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"Күнтізбе"</string>
<string name="tuner_full_zen_title" msgid="4540823317772234308">"Дыбыс деңгейін басқару элементтерімен бірге көрсету"</string>
<string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Мазаламау"</string>
<string name="volume_dnd_silent" msgid="4363882330723050727">"Дыбыс деңгейі түймелерінің төте жолы"</string>
@@ -559,4 +596,14 @@
<string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Жоғары қарай жылжыту"</string>
<string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Солға жылжыту"</string>
<string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Оңға жылжыту"</string>
+ <string name="forced_resizable_info_text" msgid="7591061837558867999">"Қолданба көп тереземен жұмыс істемеуі мүмкін"</string>
+ <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"<xliff:g id="POSITION">%1$d</xliff:g> орны, <xliff:g id="TILE_NAME">%2$s</xliff:g>. Өңдеу үшін екі рет түртіңіз."</string>
+ <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. Қосу үшін екі рет түртіңіз."</string>
+ <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"<xliff:g id="POSITION">%1$d</xliff:g> орны. Таңдау үшін екі рет түртіңіз."</string>
+ <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"<xliff:g id="TILE_NAME">%1$s</xliff:g> жылжыту"</string>
+ <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"<xliff:g id="TILE_NAME">%1$s</xliff:g> жою"</string>
+ <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="TILE_NAME">%1$s</xliff:g> <xliff:g id="POSITION">%2$d</xliff:g> орнына қосылды"</string>
+ <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"<xliff:g id="TILE_NAME">%1$s</xliff:g> жойылды"</string>
+ <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="TILE_NAME">%1$s</xliff:g> <xliff:g id="POSITION">%2$d</xliff:g> орнына жылжытылды"</string>
+ <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Жылдам параметрлер өңдегіші."</string>
</resources>
diff --git a/packages/SystemUI/res/values-kk-rKZ/strings_tv.xml b/packages/SystemUI/res/values-kk-rKZ/strings_tv.xml
index ef930b0..06c84a8 100644
--- a/packages/SystemUI/res/values-kk-rKZ/strings_tv.xml
+++ b/packages/SystemUI/res/values-kk-rKZ/strings_tv.xml
@@ -26,6 +26,5 @@
<string name="pip_hold_home" msgid="340086535668778109">"PIP басқару үшін "<b>"HOME"</b>" басып тұрыңыз"</string>
<string name="pip_onboarding_description" msgid="2882896641362814195">"PIP функциясын басқару үшін HOME түймесін басып тұрыңыз"</string>
<string name="pip_onboarding_button" msgid="3957426748484904611">"Түсіндім"</string>
- <!-- no translation found for recents_tv_dismiss (3555093879593377731) -->
- <skip />
+ <string name="recents_tv_dismiss" msgid="3555093879593377731">"Жабу"</string>
</resources>
diff --git a/packages/SystemUI/res/values-km-rKH/strings.xml b/packages/SystemUI/res/values-km-rKH/strings.xml
index 4a306da..b69f893 100644
--- a/packages/SystemUI/res/values-km-rKH/strings.xml
+++ b/packages/SystemUI/res/values-km-rKH/strings.xml
@@ -168,6 +168,8 @@
<string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"បោះបង់ <xliff:g id="APP">%s</xliff:g> ។"</string>
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> បដិសេធ។"</string>
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"កម្មវិធីថ្មីៗទាំងអស់ត្រូវបានបោះបង់។"</string>
+ <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+ <skip />
<string name="accessibility_recents_item_launched" msgid="7616039892382525203">"ចាប់ផ្ដើម <xliff:g id="APP">%s</xliff:g> ។"</string>
<string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
<string name="accessibility_notification_dismissed" msgid="854211387186306927">"បានបដិសេធការជូនដំណឹង"</string>
@@ -236,8 +238,7 @@
<string name="gps_notification_found_text" msgid="4619274244146446464">"ទីតាំងកំណត់ដោយ GPS"</string>
<string name="accessibility_location_active" msgid="2427290146138169014">"សំណើទីតាំងសកម្ម"</string>
<string name="accessibility_clear_all" msgid="5235938559247164925">"សម្អាតការជូនដំណឹងទាំងអស់។"</string>
- <!-- no translation found for notification_group_overflow_indicator (1863231301642314183) -->
- <skip />
+ <string name="notification_group_overflow_indicator" msgid="1863231301642314183">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string>
<string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"កំណត់ការជូនដំណឹង"</string>
<string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"ការកំណត់ <xliff:g id="APP_NAME">%s</xliff:g>"</string>
<string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"នឹងបង្វិលអេក្រង់ស្វ័យប្រវត្តិ។"</string>
@@ -310,8 +311,7 @@
<string name="recents_search_bar_label" msgid="8074997400187836677">"ស្វែងរក"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"មិនអាចចាប់ផ្ដើម <xliff:g id="APP">%s</xliff:g> ទេ។"</string>
<string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g> ត្រូវបានបិទដំណើរការក្នុងរបៀបសុវត្ថិភាព"</string>
- <string name="recents_history_button_label" msgid="5153358867807604821">"ប្រវត្តិ"</string>
- <string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"សម្អាត"</string>
+ <string name="recents_stack_action_button_label" msgid="6593727103310426253">"ជម្រះទាំងអស់"</string>
<string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"កម្មវិធីនេះមិនគាំទ្រផ្ទាំងវិដូច្រើនទេ"</string>
<string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"កម្មវិធីមិនគាំទ្រផ្ទាំងវិដូច្រើនទេ"</string>
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"បំបែកផ្តេក"</string>
@@ -480,8 +480,7 @@
<string name="notification_importance_max" msgid="5806278962376556491">"បង្ហាញនៅផ្នែកខាងលើបញ្ជីនៃការជូនដំណឹង លោតបង្ហាញនៅលើអេក្រង់ និងអនុញ្ញាតឲ្យបន្លឺសំឡេង"</string>
<string name="notification_more_settings" msgid="816306283396553571">"ការកំណត់ច្រើនទៀត"</string>
<string name="notification_done" msgid="5279426047273930175">"រួចរាល់"</string>
- <!-- no translation found for notification_gear_accessibility (94429150213089611) -->
- <skip />
+ <string name="notification_gear_accessibility" msgid="94429150213089611">"អង្គគ្រប់គ្រងការជូនដំណឹង <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="color_and_appearance" msgid="1254323855964993144">"ពណ៌ និងរូបរាង"</string>
<string name="night_mode" msgid="3540405868248625488">"របៀបពេលយប់"</string>
<string name="calibrate_display" msgid="5974642573432039217">"ការបង្ហាញក្រិត"</string>
@@ -501,10 +500,48 @@
<string name="battery_detail_charging_summary" msgid="1279095653533044008">"កម្មវិធីសន្សំថ្មមិនអាចប្រើបានអំឡុងពេលសាកថ្មទេ"</string>
<string name="battery_detail_switch_title" msgid="6285872470260795421">"កម្មវិធីសន្សំថ្ម"</string>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"កាត់បន្ថយប្រតិបត្តិការ និងទិន្នន័យផ្ទៃខាងក្រោយ"</string>
+ <string name="keyboard_key_button_template" msgid="6230056639734377300">"ប៊ូតុង <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="keyboard_key_home" msgid="2243500072071305073">"Home"</string>
+ <string name="keyboard_key_back" msgid="2337450286042721351">"Back"</string>
+ <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"Up"</string>
+ <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"Down"</string>
+ <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"Left"</string>
+ <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"Right"</string>
+ <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"Center"</string>
+ <string name="keyboard_key_tab" msgid="3871485650463164476">"Tab"</string>
+ <string name="keyboard_key_space" msgid="2499861316311153293">"Space"</string>
+ <string name="keyboard_key_enter" msgid="5739632123216118137">"Enter"</string>
+ <string name="keyboard_key_backspace" msgid="1559580097512385854">"Backspace"</string>
+ <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"Play/Pause"</string>
+ <string name="keyboard_key_media_stop" msgid="2859963958595908962">"Stop"</string>
+ <string name="keyboard_key_media_next" msgid="1894394911630345607">"Next"</string>
+ <string name="keyboard_key_media_previous" msgid="4256072387192967261">"Previous"</string>
+ <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"Rewind"</string>
+ <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"Fast Forward"</string>
+ <string name="keyboard_key_page_up" msgid="5654098530106845603">"Page Up"</string>
+ <string name="keyboard_key_page_down" msgid="8720502083731906136">"Page Down"</string>
+ <string name="keyboard_key_forward_del" msgid="1391451334716490176">"Delete"</string>
+ <string name="keyboard_key_move_home" msgid="2765693292069487486">"Home"</string>
+ <string name="keyboard_key_move_end" msgid="5901174332047975247">"End"</string>
+ <string name="keyboard_key_insert" msgid="8530501581636082614">"Insert"</string>
+ <string name="keyboard_key_num_lock" msgid="5052537581246772117">"Num Lock"</string>
+ <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"Numpad <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"ប្រព័ន្ធ"</string>
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"ដើម"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"ថ្មីៗ"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"ថយក្រោយ"</string>
+ <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"ការជូនដំណឹង"</string>
+ <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"ផ្លូវកាត់ក្ដារចុច"</string>
+ <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"ប្ដូរវិធីសាស្ត្របញ្ចូល"</string>
+ <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"កម្មវិធី"</string>
+ <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"ជំនួយ"</string>
+ <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"កម្មវិធីរុករក"</string>
+ <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"ទំនាក់ទំនង"</string>
+ <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"អ៊ីមែល"</string>
+ <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"IM"</string>
+ <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"តន្ត្រី"</string>
+ <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+ <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"ប្រតិទិន"</string>
<string name="tuner_full_zen_title" msgid="4540823317772234308">"បង្ហាញជាមួយការគ្រប់គ្រងកម្រិតសំឡេង"</string>
<string name="volume_and_do_not_disturb" msgid="3373784330208603030">"កុំរំខាន"</string>
<string name="volume_dnd_silent" msgid="4363882330723050727">"ផ្លូវកាត់ប៊ូតុងកម្រិតសំឡេង"</string>
@@ -559,4 +596,14 @@
<string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"ផ្លាស់ទីឡើងលើ"</string>
<string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"ផ្លាស់ទីទៅឆ្វេង"</string>
<string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"ផ្លាស់ទីទៅស្តាំ"</string>
+ <string name="forced_resizable_info_text" msgid="7591061837558867999">"កម្មវិធីអាចនឹងមិនដំណើរការជាមួយពហុវិនដូទេ"</string>
+ <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"ទីតាំង <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>, ប៉ះពីរដងដើម្បីកែ"</string>
+ <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>, ប៉ះពីរដងដើម្បីបន្ថែម"</string>
+ <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"ទីតាំង <xliff:g id="POSITION">%1$d</xliff:g>, ប៉ះពីរដងដើម្បីជ្រើស"</string>
+ <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"ផ្លាស់ទី <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"យក <xliff:g id="TILE_NAME">%1$s</xliff:g> ចេញ"</string>
+ <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="TILE_NAME">%1$s</xliff:g> ត្រូវបានបន្ថែមទៅទីតាំង <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+ <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"<xliff:g id="TILE_NAME">%1$s</xliff:g> ត្រូវបានយកចេញ"</string>
+ <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="TILE_NAME">%1$s</xliff:g> បានផ្លាស់ទីទៅទីតាំង <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+ <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"កម្មវិធីកែការកំណត់រហ័ស"</string>
</resources>
diff --git a/packages/SystemUI/res/values-km-rKH/strings_tv.xml b/packages/SystemUI/res/values-km-rKH/strings_tv.xml
index 8076010..123cb76 100644
--- a/packages/SystemUI/res/values-km-rKH/strings_tv.xml
+++ b/packages/SystemUI/res/values-km-rKH/strings_tv.xml
@@ -26,6 +26,5 @@
<string name="pip_hold_home" msgid="340086535668778109">"សង្កត់ប៊ូតុង "<b>"ដើម"</b>" ដើម្បីគ្រប់គ្រង PIP"</string>
<string name="pip_onboarding_description" msgid="2882896641362814195">"ចុច និងសង្កត់ប៊ូតុង ដើម ដើម្បីគ្រប់គ្រង PIP"</string>
<string name="pip_onboarding_button" msgid="3957426748484904611">"យល់ហើយ"</string>
- <!-- no translation found for recents_tv_dismiss (3555093879593377731) -->
- <skip />
+ <string name="recents_tv_dismiss" msgid="3555093879593377731">"បដិសេធ"</string>
</resources>
diff --git a/packages/SystemUI/res/values-kn-rIN/strings.xml b/packages/SystemUI/res/values-kn-rIN/strings.xml
index 046d5d8..1ce14dd5 100644
--- a/packages/SystemUI/res/values-kn-rIN/strings.xml
+++ b/packages/SystemUI/res/values-kn-rIN/strings.xml
@@ -168,6 +168,8 @@
<string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"<xliff:g id="APP">%s</xliff:g> ವಜಾಗೊಳಿಸು."</string>
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> ವಜಾಗೊಳಿಸಲಾಗಿದೆ."</string>
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"ಇತ್ತೀಚಿನ ಎಲ್ಲಾ ಅಪ್ಲಿಕೇಶನ್ಗಳನ್ನು ವಜಾಗೊಳಿಸಲಾಗಿದೆ."</string>
+ <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+ <skip />
<string name="accessibility_recents_item_launched" msgid="7616039892382525203">"<xliff:g id="APP">%s</xliff:g> ಪ್ರಾರಂಭಿಸಲಾಗುತ್ತಿದೆ."</string>
<string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
<string name="accessibility_notification_dismissed" msgid="854211387186306927">"ಅಧಿಸೂಚನೆ ವಜಾಗೊಂಡಿದೆ."</string>
@@ -236,8 +238,7 @@
<string name="gps_notification_found_text" msgid="4619274244146446464">"ಸ್ಥಾನವನ್ನು GPS ಮೂಲಕ ಹೊಂದಿಸಲಾಗಿದೆ"</string>
<string name="accessibility_location_active" msgid="2427290146138169014">"ಸ್ಥಾನ ವಿನಂತಿಗಳು ಸಕ್ರಿಯವಾಗಿವೆ"</string>
<string name="accessibility_clear_all" msgid="5235938559247164925">"ಎಲ್ಲಾ ಅಧಿಸೂಚನೆಗಳನ್ನು ತೆರವುಗೊಳಿಸು."</string>
- <!-- no translation found for notification_group_overflow_indicator (1863231301642314183) -->
- <skip />
+ <string name="notification_group_overflow_indicator" msgid="1863231301642314183">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string>
<string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"ಅಧಿಸೂಚನೆ ಸೆಟ್ಟಿಂಗ್ಗಳು"</string>
<string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"<xliff:g id="APP_NAME">%s</xliff:g> ಸೆಟ್ಟಿಂಗ್ಗಳು"</string>
<string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"ಪರದೆಯು ಸ್ವಯಂಚಾಲಿತವಾಗಿ ತಿರುಗುತ್ತದೆ."</string>
@@ -310,8 +311,7 @@
<string name="recents_search_bar_label" msgid="8074997400187836677">"ಹುಡುಕಾಟ"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g> ಪ್ರಾರಂಭಿಸಲು ಸಾದ್ಯವಿಲ್ಲ."</string>
<string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g> ಅನ್ನು ಸುರಕ್ಷಿತ ಮೋಡ್ನಲ್ಲಿ ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ."</string>
- <string name="recents_history_button_label" msgid="5153358867807604821">"ಇತಿಹಾಸ"</string>
- <string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"ತೆರವುಗೊಳಿಸು"</string>
+ <string name="recents_stack_action_button_label" msgid="6593727103310426253">"ಎಲ್ಲವನ್ನೂ ತೆರವುಗೊಳಿಸು"</string>
<string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"ಈ ಅಪ್ಲಿಕೇಶನ್ ಬಹು-ವಿಂಡೊಗಳನ್ನು ಬೆಂಬಲಿಸುವುದಿಲ್ಲ"</string>
<string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"ಅಪ್ಲಿಕೇಶನ್ ಬಹು-ವಿಂಡೊಗಳನ್ನು ಬೆಂಬಲಿಸುವುದಿಲ್ಲ"</string>
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"ಅಡ್ಡಲಾಗಿ ವಿಭಜಿಸಿದ"</string>
@@ -480,8 +480,7 @@
<string name="notification_importance_max" msgid="5806278962376556491">"ಅಧಿಸೂಚನೆಗಳ ಪಟ್ಟಿಯ ಮೇಲ್ಭಾಗದಲ್ಲಿ ತೋರಿಸು, ಪರದೆಯನ್ನು ವೀಕ್ಷಿಸಿ ಮತ್ತು ಧ್ವನಿ ಅನುಮತಿಸಿ"</string>
<string name="notification_more_settings" msgid="816306283396553571">"ಹೆಚ್ಚಿನ ಸೆಟ್ಟಿಂಗ್ಗಳು"</string>
<string name="notification_done" msgid="5279426047273930175">"ಮುಗಿದಿದೆ"</string>
- <!-- no translation found for notification_gear_accessibility (94429150213089611) -->
- <skip />
+ <string name="notification_gear_accessibility" msgid="94429150213089611">"<xliff:g id="APP_NAME">%1$s</xliff:g> ಅಧಿಸೂಚನೆ ನಿಯಂತ್ರಣಗಳು"</string>
<string name="color_and_appearance" msgid="1254323855964993144">"ಬಣ್ಣ ಮತ್ತು ಗೋಚರತೆ"</string>
<string name="night_mode" msgid="3540405868248625488">"ರಾತ್ರಿ ಮೋಡ್"</string>
<string name="calibrate_display" msgid="5974642573432039217">"ಅಣಿಗೊಳಿಸುವ ಪ್ರದರ್ಶನ"</string>
@@ -501,10 +500,48 @@
<string name="battery_detail_charging_summary" msgid="1279095653533044008">"ಚಾರ್ಜಿಂಗ್ ಸಮಯದಲ್ಲಿ ಬ್ಯಾಟರಿ ಸೇವರ್ ಲಭ್ಯವಿರುವುದಿಲ್ಲ"</string>
<string name="battery_detail_switch_title" msgid="6285872470260795421">"ಬ್ಯಾಟರಿ ಸೇವರ್"</string>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"ಕಾರ್ಯಕ್ಷಮತೆ ಮತ್ತು ಹಿನ್ನೆಲೆ ಡೇಟಾವನ್ನು ಕಡಿಮೆ ಮಾಡುತ್ತದೆ"</string>
+ <string name="keyboard_key_button_template" msgid="6230056639734377300">"<xliff:g id="NAME">%1$s</xliff:g> ಬಟನ್"</string>
+ <string name="keyboard_key_home" msgid="2243500072071305073">"Home"</string>
+ <string name="keyboard_key_back" msgid="2337450286042721351">"ಹಿಂದೆ"</string>
+ <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"ಮೇಲೆ"</string>
+ <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"ಕೆಳಗೆ"</string>
+ <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"ಎಡ"</string>
+ <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"ಬಲ"</string>
+ <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"ಮಧ್ಯ"</string>
+ <string name="keyboard_key_tab" msgid="3871485650463164476">"Tab"</string>
+ <string name="keyboard_key_space" msgid="2499861316311153293">"ಸ್ಪೇಸ್"</string>
+ <string name="keyboard_key_enter" msgid="5739632123216118137">"Enter"</string>
+ <string name="keyboard_key_backspace" msgid="1559580097512385854">"Backspace"</string>
+ <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"Play/Pause"</string>
+ <string name="keyboard_key_media_stop" msgid="2859963958595908962">"Stop"</string>
+ <string name="keyboard_key_media_next" msgid="1894394911630345607">"ಮುಂದೆ"</string>
+ <string name="keyboard_key_media_previous" msgid="4256072387192967261">"ಹಿಂದೆ"</string>
+ <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"Rewind"</string>
+ <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"ಫಾಸ್ಟ್ ಫಾರ್ವರ್ಡ್"</string>
+ <string name="keyboard_key_page_up" msgid="5654098530106845603">"Page Up"</string>
+ <string name="keyboard_key_page_down" msgid="8720502083731906136">"Page Down"</string>
+ <string name="keyboard_key_forward_del" msgid="1391451334716490176">"Delete"</string>
+ <string name="keyboard_key_move_home" msgid="2765693292069487486">"Home"</string>
+ <string name="keyboard_key_move_end" msgid="5901174332047975247">"End"</string>
+ <string name="keyboard_key_insert" msgid="8530501581636082614">"Insert"</string>
+ <string name="keyboard_key_num_lock" msgid="5052537581246772117">"Num Lock"</string>
+ <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"<xliff:g id="NAME">%1$s</xliff:g> ಸಂಖ್ಯೆಪ್ಯಾಡ್"</string>
<string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"ಸಿಸ್ಟಂ"</string>
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"ಮುಖಪುಟ"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"ಇತ್ತೀಚಿನವುಗಳು"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"ಹಿಂದೆ"</string>
+ <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"ಅಧಿಸೂಚನೆಗಳು"</string>
+ <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"ಕೀಬೋರ್ಡ್ ಶಾರ್ಟ್ಕಟ್ಗಳು"</string>
+ <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"ಇನ್ಪುಟ್ ವಿಧಾನ ಬದಲಿಸಿ"</string>
+ <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"ಅಪ್ಲಿಕೇಶನ್ಗಳು"</string>
+ <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"ಸಹಾಯ ಮಾಡು"</string>
+ <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"ಬ್ರೌಸರ್"</string>
+ <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"ಸಂಪರ್ಕಗಳು"</string>
+ <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"ಇಮೇಲ್"</string>
+ <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"IM"</string>
+ <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"ಸಂಗೀತ"</string>
+ <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+ <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"ಕ್ಯಾಲೆಂಡರ್"</string>
<string name="tuner_full_zen_title" msgid="4540823317772234308">"ವಾಲ್ಯೂಮ್ ನಿಯಂತ್ರಣಗಳ ಜೊತೆಗೆ ತೋರಿಸು"</string>
<string name="volume_and_do_not_disturb" msgid="3373784330208603030">"ಅಡಚಣೆ ಮಾಡಬೇಡಿ"</string>
<string name="volume_dnd_silent" msgid="4363882330723050727">"ವಾಲ್ಯೂಮ್ ಬಟನ್ಗಳ ಶಾರ್ಟ್ಕಟ್"</string>
@@ -540,8 +577,7 @@
<string name="select_keycode" msgid="7413765103381924584">"ಕೀಬೋರ್ಡ್ ಬಟನ್ ಆಯ್ಕೆಮಾಡಿ"</string>
<string name="preview" msgid="9077832302472282938">"ಪೂರ್ವವೀಕ್ಷಣೆ"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"ಟೈಲ್ಗಳನ್ನು ಸೇರಿಸಲು ಡ್ರ್ಯಾಗ್ ಮಾಡಿ"</string>
- <!-- no translation found for drag_to_remove_tiles (3361212377437088062) -->
- <skip />
+ <string name="drag_to_remove_tiles" msgid="3361212377437088062">"ತೆಗೆದುಹಾಕಲು ಇಲ್ಲಿ ಡ್ರ್ಯಾಗ್ ಮಾಡಿ"</string>
<string name="qs_edit" msgid="2232596095725105230">"ಸಂಪಾದಿಸು"</string>
<string name="tuner_time" msgid="6572217313285536011">"ಸಮಯ"</string>
<string-array name="clock_options">
@@ -560,4 +596,14 @@
<string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"ಮೇಲೆ ಸರಿಸಿ"</string>
<string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"ಎಡಕ್ಕೆ ಸರಿಸಿ"</string>
<string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"ಬಲಕ್ಕೆ ಸರಿಸಿ"</string>
+ <string name="forced_resizable_info_text" msgid="7591061837558867999">"ಬಹು ವಿಂಡೋದಲ್ಲಿ ಅಪ್ಲಿಕೇಶನ್ ಕೆಲಸ ಮಾಡದೇ ಇರಬಹುದು"</string>
+ <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"ಸ್ಥಾನ <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>. ಸಂಪಾದಿಸಲು ಡಬಲ್ ಟ್ಯಾಪ್ ಮಾಡಿ."</string>
+ <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. ಸೇರಿಸಲು ಡಬಲ್ ಟ್ಯಾಪ್ ಮಾಡಿ."</string>
+ <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"ಸ್ಥಾನ <xliff:g id="POSITION">%1$d</xliff:g>. ಆಯ್ಕೆಮಾಡಲು ಡಬಲ್ ಟ್ಯಾಪ್ ಮಾಡಿ."</string>
+ <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"<xliff:g id="TILE_NAME">%1$s</xliff:g> ಸರಿಸಿ"</string>
+ <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"<xliff:g id="TILE_NAME">%1$s</xliff:g> ತೆಗೆದುಹಾಕಿ"</string>
+ <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="POSITION">%2$d</xliff:g> ಸ್ಥಾನಕ್ಕೆ <xliff:g id="TILE_NAME">%1$s</xliff:g> ಸೇರಿಸಲಾಗಿದೆ"</string>
+ <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"<xliff:g id="TILE_NAME">%1$s</xliff:g> ತೆಗೆದುಹಾಕಲಾಗಿದೆ"</string>
+ <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="POSITION">%2$d</xliff:g> ಸ್ಥಾನಕ್ಕೆ <xliff:g id="TILE_NAME">%1$s</xliff:g> ಸೇರಿಸಲಾಗಿದೆ"</string>
+ <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"ತ್ವರಿತ ಸೆಟ್ಟಿಂಗ್ಗಳ ಸಂಪಾದಕ."</string>
</resources>
diff --git a/packages/SystemUI/res/values-kn-rIN/strings_tv.xml b/packages/SystemUI/res/values-kn-rIN/strings_tv.xml
index d275de6..6491587 100644
--- a/packages/SystemUI/res/values-kn-rIN/strings_tv.xml
+++ b/packages/SystemUI/res/values-kn-rIN/strings_tv.xml
@@ -26,6 +26,5 @@
<string name="pip_hold_home" msgid="340086535668778109">"PIP ನಿಯಂತ್ರಿಸಲು "<b>"HOME"</b>" ಕೀಯನ್ನು ಹಿಡಿದುಕೊಳ್ಳಿ"</string>
<string name="pip_onboarding_description" msgid="2882896641362814195">"PIP ನಿಯಂತ್ರಿಸಲು HOME ಬಟನ್ ಒತ್ತಿರಿ ಮತ್ತು ಹಿಡಿದುಕೊಳ್ಳಿ"</string>
<string name="pip_onboarding_button" msgid="3957426748484904611">"ಅರ್ಥವಾಯಿತು"</string>
- <!-- no translation found for recents_tv_dismiss (3555093879593377731) -->
- <skip />
+ <string name="recents_tv_dismiss" msgid="3555093879593377731">"ವಜಾಗೊಳಿಸಿ"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index 5e16258..a8a2a0a 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -168,6 +168,8 @@
<string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"<xliff:g id="APP">%s</xliff:g>을(를) 숨깁니다."</string>
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g>이(가) 제거되었습니다."</string>
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"최근 사용한 애플리케이션을 모두 닫았습니다."</string>
+ <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+ <skip />
<string name="accessibility_recents_item_launched" msgid="7616039892382525203">"<xliff:g id="APP">%s</xliff:g>을(를) 시작하는 중입니다."</string>
<string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
<string name="accessibility_notification_dismissed" msgid="854211387186306927">"알림이 제거되었습니다."</string>
@@ -236,8 +238,7 @@
<string name="gps_notification_found_text" msgid="4619274244146446464">"GPS에서 위치 설정"</string>
<string name="accessibility_location_active" msgid="2427290146138169014">"위치 요청 있음"</string>
<string name="accessibility_clear_all" msgid="5235938559247164925">"모든 알림 지우기"</string>
- <!-- no translation found for notification_group_overflow_indicator (1863231301642314183) -->
- <skip />
+ <string name="notification_group_overflow_indicator" msgid="1863231301642314183">"<xliff:g id="NUMBER">%s</xliff:g>개 더보기"</string>
<string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"알림 설정"</string>
<string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"<xliff:g id="APP_NAME">%s</xliff:g> 설정"</string>
<string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"화면이 자동으로 회전됩니다."</string>
@@ -310,8 +311,7 @@
<string name="recents_search_bar_label" msgid="8074997400187836677">"검색"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g>을(를) 시작할 수 없습니다."</string>
<string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g>은(는) 안전 모드에서 사용 중지됩니다."</string>
- <string name="recents_history_button_label" msgid="5153358867807604821">"기록"</string>
- <string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"삭제"</string>
+ <string name="recents_stack_action_button_label" msgid="6593727103310426253">"모두 지우기"</string>
<string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"이 앱은 다중 창을 지원하지 않습니다."</string>
<string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"앱이 다중 창을 지원하지 않습니다."</string>
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"수평 분할"</string>
@@ -480,8 +480,7 @@
<string name="notification_importance_max" msgid="5806278962376556491">"알림 목록 맨 위에 표시, 화면에 표시하고 소리로 알림"</string>
<string name="notification_more_settings" msgid="816306283396553571">"설정 더보기"</string>
<string name="notification_done" msgid="5279426047273930175">"완료"</string>
- <!-- no translation found for notification_gear_accessibility (94429150213089611) -->
- <skip />
+ <string name="notification_gear_accessibility" msgid="94429150213089611">"<xliff:g id="APP_NAME">%1$s</xliff:g> 알림 관리"</string>
<string name="color_and_appearance" msgid="1254323855964993144">"색상 및 모양"</string>
<string name="night_mode" msgid="3540405868248625488">"야간 모드"</string>
<string name="calibrate_display" msgid="5974642573432039217">"디스플레이 보정"</string>
@@ -501,10 +500,48 @@
<string name="battery_detail_charging_summary" msgid="1279095653533044008">"충전하는 동안 배터리 세이버는 사용할 수 없습니다."</string>
<string name="battery_detail_switch_title" msgid="6285872470260795421">"배터리 세이버"</string>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"성능 및 백그라운드 데이터를 줄입니다."</string>
+ <string name="keyboard_key_button_template" msgid="6230056639734377300">"<xliff:g id="NAME">%1$s</xliff:g> 버튼"</string>
+ <string name="keyboard_key_home" msgid="2243500072071305073">"Home"</string>
+ <string name="keyboard_key_back" msgid="2337450286042721351">"뒤로"</string>
+ <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"위쪽"</string>
+ <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"아래쪽"</string>
+ <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"왼쪽"</string>
+ <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"오른쪽"</string>
+ <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"중앙"</string>
+ <string name="keyboard_key_tab" msgid="3871485650463164476">"Tab"</string>
+ <string name="keyboard_key_space" msgid="2499861316311153293">"Space"</string>
+ <string name="keyboard_key_enter" msgid="5739632123216118137">"Enter"</string>
+ <string name="keyboard_key_backspace" msgid="1559580097512385854">"Backspace"</string>
+ <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"재생/일시중지"</string>
+ <string name="keyboard_key_media_stop" msgid="2859963958595908962">"중지"</string>
+ <string name="keyboard_key_media_next" msgid="1894394911630345607">"다음"</string>
+ <string name="keyboard_key_media_previous" msgid="4256072387192967261">"이전"</string>
+ <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"되감기"</string>
+ <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"빨리 감기"</string>
+ <string name="keyboard_key_page_up" msgid="5654098530106845603">"Page Up"</string>
+ <string name="keyboard_key_page_down" msgid="8720502083731906136">"Page Down"</string>
+ <string name="keyboard_key_forward_del" msgid="1391451334716490176">"Delete"</string>
+ <string name="keyboard_key_move_home" msgid="2765693292069487486">"Home"</string>
+ <string name="keyboard_key_move_end" msgid="5901174332047975247">"End"</string>
+ <string name="keyboard_key_insert" msgid="8530501581636082614">"Insert"</string>
+ <string name="keyboard_key_num_lock" msgid="5052537581246772117">"Num Lock"</string>
+ <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"숫자 패드 <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"시스템"</string>
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"홈"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"최근"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"뒤로"</string>
+ <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"알림"</string>
+ <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"단축키"</string>
+ <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"입력 방법 전환"</string>
+ <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"애플리케이션"</string>
+ <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"지원"</string>
+ <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"브라우저"</string>
+ <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"주소록"</string>
+ <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"이메일"</string>
+ <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"메신저"</string>
+ <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"음악"</string>
+ <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+ <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"캘린더"</string>
<string name="tuner_full_zen_title" msgid="4540823317772234308">"볼륨 컨트롤과 함께 표시"</string>
<string name="volume_and_do_not_disturb" msgid="3373784330208603030">"알림 일시중지"</string>
<string name="volume_dnd_silent" msgid="4363882330723050727">"볼륨 버튼 단축키"</string>
@@ -559,4 +596,14 @@
<string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"위로 이동"</string>
<string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"왼쪽으로 이동"</string>
<string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"오른쪽으로 이동"</string>
+ <string name="forced_resizable_info_text" msgid="7591061837558867999">"앱이 멀티 윈도우에서 작동하지 않을 수 있습니다."</string>
+ <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"위치 <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>. 수정하려면 두 번 탭하세요."</string>
+ <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. 추가하려면 두 번 탭하세요."</string>
+ <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"위치 <xliff:g id="POSITION">%1$d</xliff:g>. 선택하려면 두 번 탭하세요."</string>
+ <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"<xliff:g id="TILE_NAME">%1$s</xliff:g> 이동"</string>
+ <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"<xliff:g id="TILE_NAME">%1$s</xliff:g> 삭제"</string>
+ <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="TILE_NAME">%1$s</xliff:g> 타일이 위치 <xliff:g id="POSITION">%2$d</xliff:g>에 추가됩니다."</string>
+ <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"<xliff:g id="TILE_NAME">%1$s</xliff:g> 타일이 삭제되었습니다."</string>
+ <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="TILE_NAME">%1$s</xliff:g> 타일을 위치 <xliff:g id="POSITION">%2$d</xliff:g>(으)로 이동함"</string>
+ <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"빠른 설정 편집기"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ko/strings_tv.xml b/packages/SystemUI/res/values-ko/strings_tv.xml
index 52747b4..da3ab9e 100644
--- a/packages/SystemUI/res/values-ko/strings_tv.xml
+++ b/packages/SystemUI/res/values-ko/strings_tv.xml
@@ -26,6 +26,5 @@
<string name="pip_hold_home" msgid="340086535668778109"><b>"HOME"</b>"을 눌러 PIP 제어"</string>
<string name="pip_onboarding_description" msgid="2882896641362814195">"홈 버튼을 길게 눌러 PIP 제어"</string>
<string name="pip_onboarding_button" msgid="3957426748484904611">"확인"</string>
- <!-- no translation found for recents_tv_dismiss (3555093879593377731) -->
- <skip />
+ <string name="recents_tv_dismiss" msgid="3555093879593377731">"닫기"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ky-rKG/strings.xml b/packages/SystemUI/res/values-ky-rKG/strings.xml
index 60db439..6a2d77f 100644
--- a/packages/SystemUI/res/values-ky-rKG/strings.xml
+++ b/packages/SystemUI/res/values-ky-rKG/strings.xml
@@ -168,6 +168,8 @@
<string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"<xliff:g id="APP">%s</xliff:g> этибарга албоо."</string>
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> жок болду."</string>
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Акыркы колдонмолордун баары көз жаздымда калтырылды."</string>
+ <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+ <skip />
<string name="accessibility_recents_item_launched" msgid="7616039892382525203">"<xliff:g id="APP">%s</xliff:g> иштеп баштоодо."</string>
<string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
<string name="accessibility_notification_dismissed" msgid="854211387186306927">"Эскертме жок кылынды."</string>
@@ -236,8 +238,7 @@
<string name="gps_notification_found_text" msgid="4619274244146446464">"GPS боюнча аныкталган жайгашуу"</string>
<string name="accessibility_location_active" msgid="2427290146138169014">"Жайгаштыруу талаптары иштелүүдө"</string>
<string name="accessibility_clear_all" msgid="5235938559247164925">"Бардык эскертмелерди тазалоо."</string>
- <!-- no translation found for notification_group_overflow_indicator (1863231301642314183) -->
- <skip />
+ <string name="notification_group_overflow_indicator" msgid="1863231301642314183">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string>
<string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"Эскертме жөндөөлөрү"</string>
<string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"<xliff:g id="APP_NAME">%s</xliff:g> жөндөөлөрү"</string>
<string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Экран автоматтык түрдө бурулат."</string>
@@ -310,8 +311,7 @@
<string name="recents_search_bar_label" msgid="8074997400187836677">"издөө"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g> баштай алган жок."</string>
<string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g> коопсуз режиминде өчүрүлдү."</string>
- <string name="recents_history_button_label" msgid="5153358867807604821">"Таржымал"</string>
- <string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Тазалоо"</string>
+ <string name="recents_stack_action_button_label" msgid="6593727103310426253">"Баарын тазалоо"</string>
<string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"Бул колдонмодо бир нече терезе режими колдоого алынбайт"</string>
<string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"Колдонмодо бир нече терезе режими колдоого алынбайт"</string>
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Туурасынан бөлүү"</string>
@@ -480,8 +480,7 @@
<string name="notification_importance_max" msgid="5806278962376556491">"Эскертмелер тизмесинин эң башында көрсөтүлүп, үн менен коштолуп, экранга чыгарылсын"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Дагы жөндөөлөр"</string>
<string name="notification_done" msgid="5279426047273930175">"Аткарылды"</string>
- <!-- no translation found for notification_gear_accessibility (94429150213089611) -->
- <skip />
+ <string name="notification_gear_accessibility" msgid="94429150213089611">"<xliff:g id="APP_NAME">%1$s</xliff:g> эскертмесин башкаруу каражаттары"</string>
<string name="color_and_appearance" msgid="1254323855964993144">"Түсү жана көрүнүшү"</string>
<string name="night_mode" msgid="3540405868248625488">"Түнкү режим"</string>
<string name="calibrate_display" msgid="5974642573432039217">"Дисплейди калибрлөө"</string>
@@ -501,10 +500,48 @@
<string name="battery_detail_charging_summary" msgid="1279095653533044008">"Батареяны үнөмдөгүч түзмөк кубатталып жатканда иштебейт"</string>
<string name="battery_detail_switch_title" msgid="6285872470260795421">"Батареяны үнөмдөгүч"</string>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"Иштин майнаптуулугун начарлатып, фондук дайындарды чектейт"</string>
+ <string name="keyboard_key_button_template" msgid="6230056639734377300">"<xliff:g id="NAME">%1$s</xliff:g> баскычы"</string>
+ <string name="keyboard_key_home" msgid="2243500072071305073">"Башкы бет"</string>
+ <string name="keyboard_key_back" msgid="2337450286042721351">"Артка"</string>
+ <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"Өйдө"</string>
+ <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"Төмөн"</string>
+ <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"Солго"</string>
+ <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"Оңго"</string>
+ <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"Ортолотуу"</string>
+ <string name="keyboard_key_tab" msgid="3871485650463164476">"Өтмөк"</string>
+ <string name="keyboard_key_space" msgid="2499861316311153293">"Боштук"</string>
+ <string name="keyboard_key_enter" msgid="5739632123216118137">"Киргизүү"</string>
+ <string name="keyboard_key_backspace" msgid="1559580097512385854">"Артка өчүрүү"</string>
+ <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"Ойнотуу/Тындыруу"</string>
+ <string name="keyboard_key_media_stop" msgid="2859963958595908962">"Токтотуу"</string>
+ <string name="keyboard_key_media_next" msgid="1894394911630345607">"Кийинки"</string>
+ <string name="keyboard_key_media_previous" msgid="4256072387192967261">"Мурунку"</string>
+ <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"Артка түрүү"</string>
+ <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"Алдыга түрүү"</string>
+ <string name="keyboard_key_page_up" msgid="5654098530106845603">"Page Up"</string>
+ <string name="keyboard_key_page_down" msgid="8720502083731906136">"Page Down"</string>
+ <string name="keyboard_key_forward_del" msgid="1391451334716490176">"Жок кылуу"</string>
+ <string name="keyboard_key_move_home" msgid="2765693292069487486">"Башкы бет"</string>
+ <string name="keyboard_key_move_end" msgid="5901174332047975247">"Бүтүрүү"</string>
+ <string name="keyboard_key_insert" msgid="8530501581636082614">"Insert"</string>
+ <string name="keyboard_key_num_lock" msgid="5052537581246772117">"Num Lock"</string>
+ <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"Numpad <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"Тутум"</string>
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Башкы бет"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Акыркылар"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Артка"</string>
+ <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Эскертмелер"</string>
+ <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"Баскычтоптун кыска жолдору"</string>
+ <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"Киргизүү ыкмасын которуштуруу"</string>
+ <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"Колдонмолор"</string>
+ <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"Көмөкчү"</string>
+ <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"Серепчи"</string>
+ <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"Байланыштар"</string>
+ <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"Электрондук почта"</string>
+ <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"IM"</string>
+ <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"Музыка"</string>
+ <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+ <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"Жылнаама"</string>
<string name="tuner_full_zen_title" msgid="4540823317772234308">"Үн көзөмөлдөгүчтөрү менен көрсөтүлсүн"</string>
<string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Тынчымды алба"</string>
<string name="volume_dnd_silent" msgid="4363882330723050727">"Үндү көзөмөлдөөчү баскычтардын кыска жолдору"</string>
@@ -540,8 +577,7 @@
<string name="select_keycode" msgid="7413765103381924584">"Баскычтоптогу баскычты тандоо"</string>
<string name="preview" msgid="9077832302472282938">"Алдын ала көрүү"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"Керектүү нерселерди сүйрөп кошуңуз"</string>
- <!-- no translation found for drag_to_remove_tiles (3361212377437088062) -->
- <skip />
+ <string name="drag_to_remove_tiles" msgid="3361212377437088062">"Алып салуу үчүн бул жерге сүйрөңүз"</string>
<string name="qs_edit" msgid="2232596095725105230">"Түзөтүү"</string>
<string name="tuner_time" msgid="6572217313285536011">"Убакыт"</string>
<string-array name="clock_options">
@@ -560,4 +596,14 @@
<string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Жогору жылдыруу"</string>
<string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Солго жылдыруу"</string>
<string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Оңго жылдыруу"</string>
+ <string name="forced_resizable_info_text" msgid="7591061837558867999">"Бир нече терезе режиминде колдонмо иштебей калышы мүмкүн"</string>
+ <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"Орду - <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>. Түзөтүү үчүн эки жолу таптаңыз."</string>
+ <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. Кошуу үчүн эки жолу таптаңыз."</string>
+ <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"Орду - <xliff:g id="POSITION">%1$d</xliff:g>. Тандоо үчүн эки жолу таптаңыз."</string>
+ <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"<xliff:g id="TILE_NAME">%1$s</xliff:g> дегенди жылдыруу"</string>
+ <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"<xliff:g id="TILE_NAME">%1$s</xliff:g> дегенди алып салуу"</string>
+ <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="TILE_NAME">%1$s</xliff:g> деген <xliff:g id="POSITION">%2$d</xliff:g>-орунга кошулду"</string>
+ <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"<xliff:g id="TILE_NAME">%1$s</xliff:g> алынып салынды"</string>
+ <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="TILE_NAME">%1$s</xliff:g> деген <xliff:g id="POSITION">%2$d</xliff:g>-орунга жылдырылды"</string>
+ <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Ыкчам жөндөөлөр түзөткүчү."</string>
</resources>
diff --git a/packages/SystemUI/res/values-ky-rKG/strings_tv.xml b/packages/SystemUI/res/values-ky-rKG/strings_tv.xml
index e54aae2..b030542 100644
--- a/packages/SystemUI/res/values-ky-rKG/strings_tv.xml
+++ b/packages/SystemUI/res/values-ky-rKG/strings_tv.xml
@@ -26,6 +26,5 @@
<string name="pip_hold_home" msgid="340086535668778109"><b>"БАШКЫ БЕТ"</b>" басып туруп PIP\'ти башкарыңыз"</string>
<string name="pip_onboarding_description" msgid="2882896641362814195">"PIP башкаруу үчүн БАШКЫ БЕТ баскычын басып, кармап туруңуз"</string>
<string name="pip_onboarding_button" msgid="3957426748484904611">"Түшүндүм"</string>
- <!-- no translation found for recents_tv_dismiss (3555093879593377731) -->
- <skip />
+ <string name="recents_tv_dismiss" msgid="3555093879593377731">"Көз жаздымда калтыруу"</string>
</resources>
diff --git a/packages/SystemUI/res/values-lo-rLA/strings.xml b/packages/SystemUI/res/values-lo-rLA/strings.xml
index ecb1eb3..601cc2a 100644
--- a/packages/SystemUI/res/values-lo-rLA/strings.xml
+++ b/packages/SystemUI/res/values-lo-rLA/strings.xml
@@ -168,6 +168,8 @@
<string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"ປິດ <xliff:g id="APP">%s</xliff:g> ໄວ້."</string>
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"ປິດ <xliff:g id="APP">%s</xliff:g> ແລ້ວ."</string>
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"ທຸກແອັບພລິເຄຊັນບໍ່ດົນມານີ້ຖືກປ່ອຍໄປ."</string>
+ <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+ <skip />
<string name="accessibility_recents_item_launched" msgid="7616039892382525203">"ກຳລັງເປີດ <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
<string name="accessibility_notification_dismissed" msgid="854211387186306927">"ປິດການແຈ້ງເຕືອນແລ້ວ."</string>
@@ -236,8 +238,7 @@
<string name="gps_notification_found_text" msgid="4619274244146446464">"ສະຖານທີ່ກຳນົດໂດຍ GPS"</string>
<string name="accessibility_location_active" msgid="2427290146138169014">"ການຮ້ອງຂໍສະຖານທີ່ທີ່ເຮັດວຽກຢູ່"</string>
<string name="accessibility_clear_all" msgid="5235938559247164925">"ລຶບການແຈ້ງເຕືອນທັງໝົດ."</string>
- <!-- no translation found for notification_group_overflow_indicator (1863231301642314183) -->
- <skip />
+ <string name="notification_group_overflow_indicator" msgid="1863231301642314183">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string>
<string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"ການຕັ້ງຄ່າການແຈ້ງເຕືອນ"</string>
<string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"ການຕັ້ງຄ່າ <xliff:g id="APP_NAME">%s</xliff:g>"</string>
<string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"ໜ້າຈໍຈະໝຸນໂດຍອັດຕະໂນມັດ."</string>
@@ -310,8 +311,7 @@
<string name="recents_search_bar_label" msgid="8074997400187836677">"ຊອກຫາ"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"ບໍ່ສາມາດເລີ່ມ <xliff:g id="APP">%s</xliff:g> ໄດ້."</string>
<string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g> ຖືກປິດໃຊ້ໃນໂໝດຄວາມມປອດໄພ."</string>
- <string name="recents_history_button_label" msgid="5153358867807604821">"ປະຫວັດ"</string>
- <string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"ລຶບ"</string>
+ <string name="recents_stack_action_button_label" msgid="6593727103310426253">"ລຶບລ້າງທັງໝົດ"</string>
<string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"ແອັບນີ້ບໍ່ຮອງຮັບຫຼາຍໜ້າຈໍ"</string>
<string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"ແອັບບໍ່ຮອງຮັບຫຼາຍໜ້າຈໍ"</string>
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"ການແຍກລວງຂວາງ"</string>
@@ -480,8 +480,7 @@
<string name="notification_importance_max" msgid="5806278962376556491">"ສະແດງຢູ່ເທິງສຸດຂອງລາຍການແຈ້ງເຕືອນ, ແຈ້ງໄປໜ້າຈໍ ແລະ ອະນຸຍາດໃຫ້ໃຊ້ສຽງໄດ້"</string>
<string name="notification_more_settings" msgid="816306283396553571">"ການຕັ້ງຄ່າເພີ່ມເຕີມ"</string>
<string name="notification_done" msgid="5279426047273930175">"ສຳເລັດແລ້ວ"</string>
- <!-- no translation found for notification_gear_accessibility (94429150213089611) -->
- <skip />
+ <string name="notification_gear_accessibility" msgid="94429150213089611">"ການຄວບຄຸມການແຈ້ງເຕືອນ <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="color_and_appearance" msgid="1254323855964993144">"ສີ ແລະ ລັກສະນະ"</string>
<string name="night_mode" msgid="3540405868248625488">"ໂໝດກາງຄືນ"</string>
<string name="calibrate_display" msgid="5974642573432039217">"ປັບໜ້າຈໍ"</string>
@@ -501,10 +500,48 @@
<string name="battery_detail_charging_summary" msgid="1279095653533044008">"ຕົວປະຢັດແບັດເຕີຣີບໍ່ມີໃຫ້ນຳໃຊ້ໃນລະຫວ່າງການສາກ"</string>
<string name="battery_detail_switch_title" msgid="6285872470260795421">"ຕົວປະຢັດແບັດເຕີຣີ"</string>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"ຫຼຸດປະສິທິພາບການໃຊ້ງານ ແລະ ຂໍ້ມູນພື້ນຫຼັງ"</string>
+ <string name="keyboard_key_button_template" msgid="6230056639734377300">"ປຸ່ມ <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="keyboard_key_home" msgid="2243500072071305073">"Home"</string>
+ <string name="keyboard_key_back" msgid="2337450286042721351">"ກັບຄືນ"</string>
+ <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"ຂຶ້ນ"</string>
+ <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"ລົງ"</string>
+ <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"ຊ້າຍ"</string>
+ <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"ຂວາ"</string>
+ <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"ເຄິ່ງກາງ"</string>
+ <string name="keyboard_key_tab" msgid="3871485650463164476">"Tab"</string>
+ <string name="keyboard_key_space" msgid="2499861316311153293">"Space"</string>
+ <string name="keyboard_key_enter" msgid="5739632123216118137">"Enter"</string>
+ <string name="keyboard_key_backspace" msgid="1559580097512385854">"Backspace"</string>
+ <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"ຫຼິ້ນ/ຢຸດຊົ່ວຄາວ"</string>
+ <string name="keyboard_key_media_stop" msgid="2859963958595908962">"ຢຸດ"</string>
+ <string name="keyboard_key_media_next" msgid="1894394911630345607">"ຕໍ່ໄປ"</string>
+ <string name="keyboard_key_media_previous" msgid="4256072387192967261">"ກ່ອນໜ້າ"</string>
+ <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"ຣີວາຍກັບ"</string>
+ <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"ເລື່ອນໄປໜ້າ"</string>
+ <string name="keyboard_key_page_up" msgid="5654098530106845603">"Page Up"</string>
+ <string name="keyboard_key_page_down" msgid="8720502083731906136">"Page Down"</string>
+ <string name="keyboard_key_forward_del" msgid="1391451334716490176">"Delete"</string>
+ <string name="keyboard_key_move_home" msgid="2765693292069487486">"Home"</string>
+ <string name="keyboard_key_move_end" msgid="5901174332047975247">"End"</string>
+ <string name="keyboard_key_insert" msgid="8530501581636082614">"Insert"</string>
+ <string name="keyboard_key_num_lock" msgid="5052537581246772117">"Num Lock"</string>
+ <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"Numpad <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"ລະບົບ"</string>
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"ໜ້າຫຼັກ"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"ຫາກໍໃຊ້"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"ກັບຄືນ"</string>
+ <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"ການແຈ້ງເຕືອນ"</string>
+ <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"ປຸ່ມລັດແປ້ນພິມ"</string>
+ <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"ສະລັບຮູບແບບການປ້ອນຂໍ້ມູນ"</string>
+ <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"ແອັບພລິເຄຊັນ"</string>
+ <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"ຕົວຊ່ວຍ"</string>
+ <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"ໂປຣແກຣມທ່ອງເວັບ"</string>
+ <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"ລາຍຊື່ຜູ້ຕິດຕໍ່"</string>
+ <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"ອີເມວ"</string>
+ <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"IM"</string>
+ <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"ດົນຕີ"</string>
+ <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+ <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"ປະຕິທິນ"</string>
<string name="tuner_full_zen_title" msgid="4540823317772234308">"ສະແດງສ່ວນຄວບຄຸມສຽງ"</string>
<string name="volume_and_do_not_disturb" msgid="3373784330208603030">"ຫ້າມລົບກວນ"</string>
<string name="volume_dnd_silent" msgid="4363882330723050727">"ທາງລັດປຸ່ມສຽງ"</string>
@@ -559,4 +596,14 @@
<string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"ເລື່ອນຂຶ້ນ"</string>
<string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"ເລື່ອນຊ້າຍ"</string>
<string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"ເລື່ອນຂວາ"</string>
+ <string name="forced_resizable_info_text" msgid="7591061837558867999">"ແອັບອາດບໍ່ສາມາດໃຊ້ໄດ້ກັບຫຼາຍໜ້າຈໍ"</string>
+ <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"ຕຳແໜ່ງ <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>. ແຕະສອງເທື່ອເພື່ອແກ້ໄຂ."</string>
+ <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. ແຕະສອງເທື່ອເພື່ອເພີ່ມ."</string>
+ <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"ຕຳແໜ່ງ <xliff:g id="POSITION">%1$d</xliff:g>. ແຕະສອງເທື່ອເພື່ອເລືອກ."</string>
+ <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"ຍ້າຍ <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"ລຶບ <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="TILE_NAME">%1$s</xliff:g> ຖືກເພີ່ມໃສ່ຕຳແໜ່ງ <xliff:g id="POSITION">%2$d</xliff:g> ແລ້ວ"</string>
+ <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"ລຶບ <xliff:g id="TILE_NAME">%1$s</xliff:g> ອອກແລ້ວ"</string>
+ <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="TILE_NAME">%1$s</xliff:g> ຍ້າຍໄປຕຳແໜ່ງ <xliff:g id="POSITION">%2$d</xliff:g> ແລ້ວ"</string>
+ <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"ຕົວແກ້ໄຂການຕັ້ງຄ່າດ່ວນ"</string>
</resources>
diff --git a/packages/SystemUI/res/values-lo-rLA/strings_tv.xml b/packages/SystemUI/res/values-lo-rLA/strings_tv.xml
index 911dcf9..6e36d3f 100644
--- a/packages/SystemUI/res/values-lo-rLA/strings_tv.xml
+++ b/packages/SystemUI/res/values-lo-rLA/strings_tv.xml
@@ -26,6 +26,5 @@
<string name="pip_hold_home" msgid="340086535668778109">"ກົດ "<b>"HOME"</b>" ຄ້າງໄວ້ເພື່ອຄວບຄຸມ PIP"</string>
<string name="pip_onboarding_description" msgid="2882896641362814195">"ແຕະປຸ່ມ HOME ຄ້າງໄວ້ເພື່ອຄວບຄຸມຮູບນ້ອຍ"</string>
<string name="pip_onboarding_button" msgid="3957426748484904611">"ເຂົ້າໃຈແລ້ວ"</string>
- <!-- no translation found for recents_tv_dismiss (3555093879593377731) -->
- <skip />
+ <string name="recents_tv_dismiss" msgid="3555093879593377731">"ປິດໄວ້"</string>
</resources>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index 4de42c0..866abf3 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -170,6 +170,8 @@
<string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Atsisakyti <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"Atsisakyta programos „<xliff:g id="APP">%s</xliff:g>“."</string>
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Atsisakyta visų naujausių programų."</string>
+ <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+ <skip />
<string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Paleidžiama <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_task_header" msgid="1437183540924535457">"„<xliff:g id="APP">%1$s</xliff:g>“ <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
<string name="accessibility_notification_dismissed" msgid="854211387186306927">"Pranešimo atsisakyta."</string>
@@ -238,8 +240,7 @@
<string name="gps_notification_found_text" msgid="4619274244146446464">"GPS nustatyta vieta"</string>
<string name="accessibility_location_active" msgid="2427290146138169014">"Vietovės užklausos aktyvios"</string>
<string name="accessibility_clear_all" msgid="5235938559247164925">"Išvalyti visus pranešimus."</string>
- <!-- no translation found for notification_group_overflow_indicator (1863231301642314183) -->
- <skip />
+ <string name="notification_group_overflow_indicator" msgid="1863231301642314183">"Dar <xliff:g id="NUMBER">%s</xliff:g>"</string>
<string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"Pranešimų nustatymai"</string>
<string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"„<xliff:g id="APP_NAME">%s</xliff:g>“ nustatymai"</string>
<string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Ekranas bus sukamas automatiškai."</string>
@@ -312,8 +313,7 @@
<string name="recents_search_bar_label" msgid="8074997400187836677">"paieška"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"Nepavyko paleisti <xliff:g id="APP">%s</xliff:g>."</string>
<string name="recents_launch_disabled_message" msgid="1624523193008871793">"Programa „<xliff:g id="APP">%s</xliff:g>“ išjungta saugos režimu."</string>
- <string name="recents_history_button_label" msgid="5153358867807604821">"Istorija"</string>
- <string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Išvalyti"</string>
+ <string name="recents_stack_action_button_label" msgid="6593727103310426253">"Išvalyti viską"</string>
<string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"Ši programa nepalaiko kelių langų režimo"</string>
<string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"Programa nepalaiko kelių langų režimo"</string>
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Horizontalus skaidymas"</string>
@@ -482,8 +482,7 @@
<string name="notification_importance_max" msgid="5806278962376556491">"Rodyti pranešimų sąrašo viršuje, rodyti ekrane ir leisti skambėti"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Daugiau nustatymų"</string>
<string name="notification_done" msgid="5279426047273930175">"Atlikta"</string>
- <!-- no translation found for notification_gear_accessibility (94429150213089611) -->
- <skip />
+ <string name="notification_gear_accessibility" msgid="94429150213089611">"„<xliff:g id="APP_NAME">%1$s</xliff:g>“ pranešimų valdikliai"</string>
<string name="color_and_appearance" msgid="1254323855964993144">"Spalva ir išvaizda"</string>
<string name="night_mode" msgid="3540405868248625488">"Naktinis režimas"</string>
<string name="calibrate_display" msgid="5974642573432039217">"Kalibruoti ekraną"</string>
@@ -503,10 +502,48 @@
<string name="battery_detail_charging_summary" msgid="1279095653533044008">"Akumuliatoriaus tausojimo priemonė nepasiekiama įkraunant"</string>
<string name="battery_detail_switch_title" msgid="6285872470260795421">"Akumuliatoriaus tausojimo priemonė"</string>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"Sumažinamas našumas ir foninių duomenų naudojimas"</string>
+ <string name="keyboard_key_button_template" msgid="6230056639734377300">"Mygtukas <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="keyboard_key_home" msgid="2243500072071305073">"Pagrindinis"</string>
+ <string name="keyboard_key_back" msgid="2337450286042721351">"Atgal"</string>
+ <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"Aukštyn"</string>
+ <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"Žemyn"</string>
+ <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"Kairėn"</string>
+ <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"Dešinėn"</string>
+ <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"Centras"</string>
+ <string name="keyboard_key_tab" msgid="3871485650463164476">"Tabuliavimo klavišas"</string>
+ <string name="keyboard_key_space" msgid="2499861316311153293">"Tarpas"</string>
+ <string name="keyboard_key_enter" msgid="5739632123216118137">"Įvesti"</string>
+ <string name="keyboard_key_backspace" msgid="1559580097512385854">"Naikinimo klavišas"</string>
+ <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"Leisti / pristabdyti"</string>
+ <string name="keyboard_key_media_stop" msgid="2859963958595908962">"Sustabdyti"</string>
+ <string name="keyboard_key_media_next" msgid="1894394911630345607">"Kitas"</string>
+ <string name="keyboard_key_media_previous" msgid="4256072387192967261">"Ankstesnis"</string>
+ <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"Sukti atgal"</string>
+ <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"Sukti pirmyn"</string>
+ <string name="keyboard_key_page_up" msgid="5654098530106845603">"Ankstesnis puslapis"</string>
+ <string name="keyboard_key_page_down" msgid="8720502083731906136">"Tolesnis puslapis"</string>
+ <string name="keyboard_key_forward_del" msgid="1391451334716490176">"Ištrinti"</string>
+ <string name="keyboard_key_move_home" msgid="2765693292069487486">"Pagrindinis"</string>
+ <string name="keyboard_key_move_end" msgid="5901174332047975247">"Baigti"</string>
+ <string name="keyboard_key_insert" msgid="8530501581636082614">"Įterpti"</string>
+ <string name="keyboard_key_num_lock" msgid="5052537581246772117">"Skaičių režimas"</string>
+ <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"Klaviatūros skaitmenų sritis <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"Sistema"</string>
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Pagrindinis ekranas"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Naujausios veiklos ekranas"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Atgal"</string>
+ <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Pranešimai"</string>
+ <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"Spartieji klavišai"</string>
+ <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"Perjungti įvesties metodą"</string>
+ <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"Programos"</string>
+ <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"Pagalbinė programa"</string>
+ <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"Naršyklė"</string>
+ <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"Kontaktai"</string>
+ <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"El. paštas"</string>
+ <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"TP"</string>
+ <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"Muzika"</string>
+ <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+ <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"Kalendorius"</string>
<string name="tuner_full_zen_title" msgid="4540823317772234308">"Rodyti su garsumo valdikliais"</string>
<string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Netrukdymo režimas"</string>
<string name="volume_dnd_silent" msgid="4363882330723050727">"Garsumo mygtukų spartusis klavišas"</string>
@@ -561,4 +598,14 @@
<string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Perkelti aukštyn"</string>
<string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Perkelti kairėn"</string>
<string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Perkelti dešinėn"</string>
+ <string name="forced_resizable_info_text" msgid="7591061837558867999">"Naudojant kelių langų funkciją programa gali neveikti"</string>
+ <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"<xliff:g id="POSITION">%1$d</xliff:g> padėtis, išklotinės elementas „<xliff:g id="TILE_NAME">%2$s</xliff:g>“. Dukart palieskite, kad redaguotumėte."</string>
+ <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"Išklotinės elementas „<xliff:g id="TILE_NAME">%1$s</xliff:g>“. Dukart palieskite, kad pridėtumėte."</string>
+ <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"<xliff:g id="POSITION">%1$d</xliff:g> padėtis. Dukart palieskite, kad pasirinktumėte."</string>
+ <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"Perkelti išklotinės elementą „<xliff:g id="TILE_NAME">%1$s</xliff:g>“"</string>
+ <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"Pašalinti išklotinės elementą „<xliff:g id="TILE_NAME">%1$s</xliff:g>“"</string>
+ <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"Išklotinės elementas „<xliff:g id="TILE_NAME">%1$s</xliff:g>“ pridėtas prie <xliff:g id="POSITION">%2$d</xliff:g> padėties"</string>
+ <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"Išklotinės elementas „<xliff:g id="TILE_NAME">%1$s</xliff:g>“ pašalintas"</string>
+ <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"Išklotinės elementas „<xliff:g id="TILE_NAME">%1$s</xliff:g>“ perkeltas į <xliff:g id="POSITION">%2$d</xliff:g> padėtį"</string>
+ <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Sparčiųjų nustatymų redagavimo priemonė."</string>
</resources>
diff --git a/packages/SystemUI/res/values-lt/strings_tv.xml b/packages/SystemUI/res/values-lt/strings_tv.xml
index 928b4c7..c8fce8a 100644
--- a/packages/SystemUI/res/values-lt/strings_tv.xml
+++ b/packages/SystemUI/res/values-lt/strings_tv.xml
@@ -26,6 +26,5 @@
<string name="pip_hold_home" msgid="340086535668778109">"Kad vald. PIP, pal. pasp. m. "<b>"PAGRINDINIS"</b></string>
<string name="pip_onboarding_description" msgid="2882896641362814195">"Jei norite valdyti PIP, paspauskite ir palaikykite pagrindinio puslapio mygtuką"</string>
<string name="pip_onboarding_button" msgid="3957426748484904611">"Supratau"</string>
- <!-- no translation found for recents_tv_dismiss (3555093879593377731) -->
- <skip />
+ <string name="recents_tv_dismiss" msgid="3555093879593377731">"Atsisakyti"</string>
</resources>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index f473971..9c32b31 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -169,6 +169,8 @@
<string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Nerādīt lietotni <xliff:g id="APP">%s</xliff:g>"</string>
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"Lietotne <xliff:g id="APP">%s</xliff:g> vairs netiek rādīta."</string>
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Visas nesen izmantotās lietojumprogrammas tika noņemtas."</string>
+ <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+ <skip />
<string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Notiek lietotnes <xliff:g id="APP">%s</xliff:g> palaišana."</string>
<string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
<string name="accessibility_notification_dismissed" msgid="854211387186306927">"Paziņojums netiek rādīts."</string>
@@ -310,8 +312,7 @@
<string name="recents_search_bar_label" msgid="8074997400187836677">"Meklēt"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"Nevarēja palaist lietotni <xliff:g id="APP">%s</xliff:g>."</string>
<string name="recents_launch_disabled_message" msgid="1624523193008871793">"Lietotne <xliff:g id="APP">%s</xliff:g> ir atspējota drošajā režīmā."</string>
- <string name="recents_history_button_label" msgid="5153358867807604821">"Vēsture"</string>
- <string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Notīrīt"</string>
+ <string name="recents_stack_action_button_label" msgid="6593727103310426253">"Notīrīt visu"</string>
<string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"Šajā lietotnē netiek atbalstīts vairāku logu režīms."</string>
<string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"Lietotnē netiek atbalstīts vairāku logu režīms"</string>
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Horizontāls dalījums"</string>
@@ -500,10 +501,48 @@
<string name="battery_detail_charging_summary" msgid="1279095653533044008">"Akumulatora jaudas taupīšanas režīms uzlādes laikā nav pieejams."</string>
<string name="battery_detail_switch_title" msgid="6285872470260795421">"Akumulatora jaudas taupīšanas režīms"</string>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"Samazina veiktspēju un fona datus."</string>
+ <string name="keyboard_key_button_template" msgid="6230056639734377300">"Poga <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="keyboard_key_home" msgid="2243500072071305073">"Sākumvietas taustiņš"</string>
+ <string name="keyboard_key_back" msgid="2337450286042721351">"Atpakaļ"</string>
+ <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"Uz augšu"</string>
+ <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"Uz leju"</string>
+ <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"Pa kreisi"</string>
+ <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"Pa labi"</string>
+ <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"Centrā"</string>
+ <string name="keyboard_key_tab" msgid="3871485650463164476">"Tabulēšanas taustiņš"</string>
+ <string name="keyboard_key_space" msgid="2499861316311153293">"Atstarpe"</string>
+ <string name="keyboard_key_enter" msgid="5739632123216118137">"Ievadīšanas taustiņš"</string>
+ <string name="keyboard_key_backspace" msgid="1559580097512385854">"Atpakaļatkāpes taustiņš"</string>
+ <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"Atskaņot/apturēt"</string>
+ <string name="keyboard_key_media_stop" msgid="2859963958595908962">"Apturēt"</string>
+ <string name="keyboard_key_media_next" msgid="1894394911630345607">"Nākamais"</string>
+ <string name="keyboard_key_media_previous" msgid="4256072387192967261">"Iepriekšējais"</string>
+ <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"Attīt atpakaļ"</string>
+ <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"Pārtīt uz priekšu"</string>
+ <string name="keyboard_key_page_up" msgid="5654098530106845603">"Lapa uz augšu"</string>
+ <string name="keyboard_key_page_down" msgid="8720502083731906136">"Lapa uz leju"</string>
+ <string name="keyboard_key_forward_del" msgid="1391451334716490176">"Dzēšanas taustiņš"</string>
+ <string name="keyboard_key_move_home" msgid="2765693292069487486">"Sākumvietas taustiņš"</string>
+ <string name="keyboard_key_move_end" msgid="5901174332047975247">"Beigvietas taustiņš"</string>
+ <string name="keyboard_key_insert" msgid="8530501581636082614">"Ievietošanas taustiņš"</string>
+ <string name="keyboard_key_num_lock" msgid="5052537581246772117">"Ciparslēga taustiņš"</string>
+ <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"Cipartastatūra <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"Sistēma"</string>
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Sākums"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Pēdējie"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Atpakaļ"</string>
+ <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Paziņojumi"</string>
+ <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"Īsinājumtaustiņi"</string>
+ <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"Pārslēgt ievades metodi"</string>
+ <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"Lietojumprogrammas"</string>
+ <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"Palīgs"</string>
+ <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"Pārlūkprogramma"</string>
+ <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"Kontaktpersonas"</string>
+ <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"E-pasts"</string>
+ <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"Tūlītējā ziņojumapmaiņa"</string>
+ <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"Mūzika"</string>
+ <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+ <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"Kalendārs"</string>
<string name="tuner_full_zen_title" msgid="4540823317772234308">"Rādīt ar skaļuma vadīklām"</string>
<string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Netraucēt"</string>
<string name="volume_dnd_silent" msgid="4363882330723050727">"Skaļuma pogu saīsne"</string>
@@ -558,4 +597,14 @@
<string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Pārvietot uz augšu"</string>
<string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Pārvietot pa kreisi"</string>
<string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Pārvietot pa labi"</string>
+ <string name="forced_resizable_info_text" msgid="7591061837558867999">"Iespējams, lietotnē nedarbosies vairāku logu režīms."</string>
+ <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"<xliff:g id="POSITION">%1$d</xliff:g>. pozīcija, <xliff:g id="TILE_NAME">%2$s</xliff:g>. Lai rediģētu, veiciet dubultskārienu."</string>
+ <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. Lai pievienotu, veiciet dubultskārienu."</string>
+ <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"<xliff:g id="POSITION">%1$d</xliff:g>. pozīcija. Lai atlasītu, veiciet dubultskārienu."</string>
+ <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"Pārvietot elementu <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"Noņemt elementu <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"Elements <xliff:g id="TILE_NAME">%1$s</xliff:g> ir pievienots <xliff:g id="POSITION">%2$d</xliff:g>. pozīcijā"</string>
+ <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"Elements <xliff:g id="TILE_NAME">%1$s</xliff:g> ir noņemts"</string>
+ <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"Elements <xliff:g id="TILE_NAME">%1$s</xliff:g> ir pārvietots uz <xliff:g id="POSITION">%2$d</xliff:g>. pozīciju"</string>
+ <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Ātro iestatījumu redaktors."</string>
</resources>
diff --git a/packages/SystemUI/res/values-mk-rMK/strings.xml b/packages/SystemUI/res/values-mk-rMK/strings.xml
index 1666273..7f2fc15 100644
--- a/packages/SystemUI/res/values-mk-rMK/strings.xml
+++ b/packages/SystemUI/res/values-mk-rMK/strings.xml
@@ -168,6 +168,8 @@
<string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Отфрли <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> е отфрлена."</string>
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Сите неодамнешни апликации се отфрлени."</string>
+ <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+ <skip />
<string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Се стартува <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
<string name="accessibility_notification_dismissed" msgid="854211387186306927">"Известувањето е отфрлено."</string>
@@ -236,8 +238,7 @@
<string name="gps_notification_found_text" msgid="4619274244146446464">"Локацијата е поставена со ГПС"</string>
<string name="accessibility_location_active" msgid="2427290146138169014">"Активни барања за локација"</string>
<string name="accessibility_clear_all" msgid="5235938559247164925">"Исчисти ги сите известувања."</string>
- <!-- no translation found for notification_group_overflow_indicator (1863231301642314183) -->
- <skip />
+ <string name="notification_group_overflow_indicator" msgid="1863231301642314183">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string>
<string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"Поставки на известувања"</string>
<string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"Поставки на <xliff:g id="APP_NAME">%s</xliff:g>"</string>
<string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Екранот ќе ротира автоматски."</string>
@@ -310,8 +311,7 @@
<string name="recents_search_bar_label" msgid="8074997400187836677">"пребарај"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g> не може да се вклучи."</string>
<string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g> е оневозможен во безбеден режим."</string>
- <string name="recents_history_button_label" msgid="5153358867807604821">"Историја"</string>
- <string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Исчисти"</string>
+ <string name="recents_stack_action_button_label" msgid="6593727103310426253">"Исчисти ги сите"</string>
<string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"Апликацијава не поддржува повеќе прозорци"</string>
<string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"Апликацијата не поддржува повеќе прозорци"</string>
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Раздели хоризонтално"</string>
@@ -480,8 +480,7 @@
<string name="notification_importance_max" msgid="5806278962376556491">"Прикажувај ги на врвот на списокот со известувања, ѕиркање на екранот и овозможи звук"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Повеќе поставки"</string>
<string name="notification_done" msgid="5279426047273930175">"Готово"</string>
- <!-- no translation found for notification_gear_accessibility (94429150213089611) -->
- <skip />
+ <string name="notification_gear_accessibility" msgid="94429150213089611">"Контроли за известувања на <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="color_and_appearance" msgid="1254323855964993144">"Боја и изглед"</string>
<string name="night_mode" msgid="3540405868248625488">"Ноќен режим"</string>
<string name="calibrate_display" msgid="5974642573432039217">"Калибрирај го екранот"</string>
@@ -501,10 +500,48 @@
<string name="battery_detail_charging_summary" msgid="1279095653533044008">"Штедачот на батерија не е достапен при полнење"</string>
<string name="battery_detail_switch_title" msgid="6285872470260795421">"Штедач на батерија"</string>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"Ја намалува изведбата и податоците во заднина"</string>
+ <string name="keyboard_key_button_template" msgid="6230056639734377300">"Копче <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="keyboard_key_home" msgid="2243500072071305073">"Почетна страница"</string>
+ <string name="keyboard_key_back" msgid="2337450286042721351">"Назад"</string>
+ <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"Стрелка нагоре"</string>
+ <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"Стрелка надолу"</string>
+ <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"Стрелка налево"</string>
+ <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"Стрелка надесно"</string>
+ <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"Центар"</string>
+ <string name="keyboard_key_tab" msgid="3871485650463164476">"Картичка"</string>
+ <string name="keyboard_key_space" msgid="2499861316311153293">"Празно место"</string>
+ <string name="keyboard_key_enter" msgid="5739632123216118137">"Внеси"</string>
+ <string name="keyboard_key_backspace" msgid="1559580097512385854">"Бришење наназад"</string>
+ <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"Пушти/Паузирај"</string>
+ <string name="keyboard_key_media_stop" msgid="2859963958595908962">"Сопри"</string>
+ <string name="keyboard_key_media_next" msgid="1894394911630345607">"Следно"</string>
+ <string name="keyboard_key_media_previous" msgid="4256072387192967261">"Претходно"</string>
+ <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"Премотување наназад"</string>
+ <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"Брзо премотување нанапред"</string>
+ <string name="keyboard_key_page_up" msgid="5654098530106845603">"Страница нагоре"</string>
+ <string name="keyboard_key_page_down" msgid="8720502083731906136">"Страница надолу"</string>
+ <string name="keyboard_key_forward_del" msgid="1391451334716490176">"Избриши"</string>
+ <string name="keyboard_key_move_home" msgid="2765693292069487486">"Почетна страница"</string>
+ <string name="keyboard_key_move_end" msgid="5901174332047975247">"Крај"</string>
+ <string name="keyboard_key_insert" msgid="8530501581636082614">"Вметни"</string>
+ <string name="keyboard_key_num_lock" msgid="5052537581246772117">"Num Lock"</string>
+ <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"Numpad <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"Систем"</string>
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Почетна страница"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Неодамнешни"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Назад"</string>
+ <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Известувања"</string>
+ <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"Кратенки на тастатурата"</string>
+ <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"Префрли метод за внесување"</string>
+ <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"Апликации"</string>
+ <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"Помош"</string>
+ <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"Прелистувач"</string>
+ <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"Контакти"</string>
+ <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"Е-пошта"</string>
+ <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"IM"</string>
+ <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"Музика"</string>
+ <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+ <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"Календар"</string>
<string name="tuner_full_zen_title" msgid="4540823317772234308">"Прикажи со контроли за јачина на звук"</string>
<string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Не вознемирувај"</string>
<string name="volume_dnd_silent" msgid="4363882330723050727">"Кратенка за копчињата за јачина на звук"</string>
@@ -559,4 +596,14 @@
<string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Преместете нагоре"</string>
<string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Преместете налево"</string>
<string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Преместете надесно"</string>
+ <string name="forced_resizable_info_text" msgid="7591061837558867999">"Апликацијата може да не работи со повеќе прозорци"</string>
+ <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"Место <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>. Допрете двапати за уредување."</string>
+ <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. Допрете двапати за додавање."</string>
+ <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"Место <xliff:g id="POSITION">%1$d</xliff:g>. Допрете двапати за избирање."</string>
+ <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"Преместете <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"Отстранете <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="TILE_NAME">%1$s</xliff:g> е додадена на место <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+ <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"<xliff:g id="TILE_NAME">%1$s</xliff:g> е отстранета"</string>
+ <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="TILE_NAME">%1$s</xliff:g> е преместена на место <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+ <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Уредник за брзи поставки."</string>
</resources>
diff --git a/packages/SystemUI/res/values-mk-rMK/strings_tv.xml b/packages/SystemUI/res/values-mk-rMK/strings_tv.xml
index 10bf41f..2d6da0c 100644
--- a/packages/SystemUI/res/values-mk-rMK/strings_tv.xml
+++ b/packages/SystemUI/res/values-mk-rMK/strings_tv.xml
@@ -26,6 +26,5 @@
<string name="pip_hold_home" msgid="340086535668778109">"Задржете "<b>"ДОМА"</b>" за кон. PIP"</string>
<string name="pip_onboarding_description" msgid="2882896641362814195">"Притиснете и задржете го копчето ДОМА за контролирање PIP"</string>
<string name="pip_onboarding_button" msgid="3957426748484904611">"Разбрав"</string>
- <!-- no translation found for recents_tv_dismiss (3555093879593377731) -->
- <skip />
+ <string name="recents_tv_dismiss" msgid="3555093879593377731">"Отфрли"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ml-rIN/strings.xml b/packages/SystemUI/res/values-ml-rIN/strings.xml
index 882f189..dfe992c 100644
--- a/packages/SystemUI/res/values-ml-rIN/strings.xml
+++ b/packages/SystemUI/res/values-ml-rIN/strings.xml
@@ -168,6 +168,8 @@
<string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"<xliff:g id="APP">%s</xliff:g> നിരസിക്കുക."</string>
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> നിരസിച്ചു."</string>
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"അടുത്തിടെയുള്ള എല്ലാ അപ്ലിക്കേഷനും നിരസിച്ചു."</string>
+ <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+ <skip />
<string name="accessibility_recents_item_launched" msgid="7616039892382525203">"<xliff:g id="APP">%s</xliff:g> ആരംഭിക്കുന്നു."</string>
<string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
<string name="accessibility_notification_dismissed" msgid="854211387186306927">"അറിയിപ്പ് നിരസിച്ചു."</string>
@@ -236,8 +238,7 @@
<string name="gps_notification_found_text" msgid="4619274244146446464">"ലൊക്കേഷൻ സജ്ജീകരിച്ചത് GPS ആണ്"</string>
<string name="accessibility_location_active" msgid="2427290146138169014">"ലൊക്കേഷൻ അഭ്യർത്ഥനകൾ സജീവമാണ്"</string>
<string name="accessibility_clear_all" msgid="5235938559247164925">"എല്ലാ വിവരങ്ങളും മായ്ക്കുക."</string>
- <!-- no translation found for notification_group_overflow_indicator (1863231301642314183) -->
- <skip />
+ <string name="notification_group_overflow_indicator" msgid="1863231301642314183">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string>
<string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"അറിയിപ്പ് ക്രമീകരണങ്ങൾ"</string>
<string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"<xliff:g id="APP_NAME">%s</xliff:g> ക്രമീകരണങ്ങൾ"</string>
<string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"സ്ക്രീൻ യാന്ത്രികമായി തിരിയും."</string>
@@ -310,8 +311,7 @@
<string name="recents_search_bar_label" msgid="8074997400187836677">"തിരയുക"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g> ആരംഭിക്കാനായില്ല."</string>
<string name="recents_launch_disabled_message" msgid="1624523193008871793">"സുരക്ഷിത മോഡിൽ <xliff:g id="APP">%s</xliff:g> പ്രവർത്തനരഹിതമാക്കിയിരിക്കുന്നു."</string>
- <string name="recents_history_button_label" msgid="5153358867807604821">"ചരിത്രം"</string>
- <string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"മായ്ക്കുക"</string>
+ <string name="recents_stack_action_button_label" msgid="6593727103310426253">"എല്ലാം മായ്ക്കുക"</string>
<string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"ഒന്നിലധികം വിൻഡോകളെ ഈ ആപ്പ് പിന്തുണയ്ക്കുന്നില്ല"</string>
<string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"ഒന്നിലധികം വിൻഡോകളെ ആപ്പ് പിന്തുണയ്ക്കുന്നില്ല"</string>
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"തിരശ്ചീനമായി വേർതിരിക്കുക"</string>
@@ -480,8 +480,7 @@
<string name="notification_importance_max" msgid="5806278962376556491">"അറിയിപ്പ് ലിസ്റ്റിന്റെ ഏറ്റവും മുകളിൽ കാണിക്കുക, ശബ്ദമുണ്ടാക്കുക"</string>
<string name="notification_more_settings" msgid="816306283396553571">"കൂടുതൽ ക്രമീകരണം"</string>
<string name="notification_done" msgid="5279426047273930175">"പൂർത്തിയായി"</string>
- <!-- no translation found for notification_gear_accessibility (94429150213089611) -->
- <skip />
+ <string name="notification_gear_accessibility" msgid="94429150213089611">"<xliff:g id="APP_NAME">%1$s</xliff:g> അറിയിപ്പ് നിയന്ത്രണങ്ങൾ"</string>
<string name="color_and_appearance" msgid="1254323855964993144">"വർണ്ണവും രൂപഭാവവും"</string>
<string name="night_mode" msgid="3540405868248625488">"നൈറ്റ് മോഡ്"</string>
<string name="calibrate_display" msgid="5974642573432039217">"ഡിസ്പ്ലേ കാലിബ്രേറ്റുചെയ്യുക"</string>
@@ -501,10 +500,48 @@
<string name="battery_detail_charging_summary" msgid="1279095653533044008">"ചാർജുചെയ്യുന്ന സമയത്ത് ബാറ്ററി സേവർ ലഭ്യമല്ല"</string>
<string name="battery_detail_switch_title" msgid="6285872470260795421">"ബാറ്ററി സേവർ"</string>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"പ്രവർത്തനവും പശ്ചാത്തല ഡാറ്റയും കുറയ്ക്കുന്നു"</string>
+ <string name="keyboard_key_button_template" msgid="6230056639734377300">"ബട്ടൺ <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="keyboard_key_home" msgid="2243500072071305073">"ഹോം"</string>
+ <string name="keyboard_key_back" msgid="2337450286042721351">"ബാക്ക്"</string>
+ <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"മുകളിലേക്ക്"</string>
+ <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"താഴേക്ക്"</string>
+ <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"ഇടത്"</string>
+ <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"വലത്"</string>
+ <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"മധ്യം"</string>
+ <string name="keyboard_key_tab" msgid="3871485650463164476">"ടാബ്"</string>
+ <string name="keyboard_key_space" msgid="2499861316311153293">"സ്പെയ്സ്"</string>
+ <string name="keyboard_key_enter" msgid="5739632123216118137">"എന്റർ"</string>
+ <string name="keyboard_key_backspace" msgid="1559580097512385854">"ബാക്ക്സ്പെയ്സ്"</string>
+ <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"പ്ലേ ചെയ്യുക/താൽക്കാലികമായി നിർത്തുക"</string>
+ <string name="keyboard_key_media_stop" msgid="2859963958595908962">"നിർത്തുക"</string>
+ <string name="keyboard_key_media_next" msgid="1894394911630345607">"അടുത്തത്"</string>
+ <string name="keyboard_key_media_previous" msgid="4256072387192967261">"മുമ്പത്തേത്"</string>
+ <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"റിവൈൻഡ്"</string>
+ <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"ഫാസ്റ്റ് ഫോർവേഡ്"</string>
+ <string name="keyboard_key_page_up" msgid="5654098530106845603">"പേജ് അപ്പ്"</string>
+ <string name="keyboard_key_page_down" msgid="8720502083731906136">"പേജ് ഡൗൺ"</string>
+ <string name="keyboard_key_forward_del" msgid="1391451334716490176">"ഡിലീറ്റ്"</string>
+ <string name="keyboard_key_move_home" msgid="2765693292069487486">"ഹോം"</string>
+ <string name="keyboard_key_move_end" msgid="5901174332047975247">"എൻഡ്"</string>
+ <string name="keyboard_key_insert" msgid="8530501581636082614">"ഇൻസേർട്ട്"</string>
+ <string name="keyboard_key_num_lock" msgid="5052537581246772117">"നം ലോക്ക്"</string>
+ <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"നംപാഡ് <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"സിസ്റ്റം"</string>
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"വീട്"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"പുതിയവ"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"മടങ്ങുക"</string>
+ <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"അറിയിപ്പുകൾ"</string>
+ <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"കീബോർഡ് കുറുക്കുവഴികൾ"</string>
+ <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"ടൈപ്പിംഗ് രീതി മാറുക"</string>
+ <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"അപ്ലിക്കേഷനുകൾ"</string>
+ <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"അസിസ്റ്റ്"</string>
+ <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"ബ്രൗസർ"</string>
+ <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"കോൺടാക്റ്റുകൾ"</string>
+ <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"ഇമെയിൽ"</string>
+ <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"IM"</string>
+ <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"സംഗീതം"</string>
+ <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+ <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"കലണ്ടർ"</string>
<string name="tuner_full_zen_title" msgid="4540823317772234308">"വോളിയം നിയന്ത്രണങ്ങളോടൊപ്പം കാണിക്കുക"</string>
<string name="volume_and_do_not_disturb" msgid="3373784330208603030">"ശല്യപ്പെടുത്തരുത്"</string>
<string name="volume_dnd_silent" msgid="4363882330723050727">"വോളിയം ബട്ടൺ കുറുക്കുവഴി"</string>
@@ -540,8 +577,7 @@
<string name="select_keycode" msgid="7413765103381924584">"കീബോർഡ് ബട്ടൺ തിരഞ്ഞെടുക്കൂ"</string>
<string name="preview" msgid="9077832302472282938">"പ്രിവ്യു നടത്തുക"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"ടൈലുകൾ ചേർക്കുന്നതിന് വലിച്ചിടുക"</string>
- <!-- no translation found for drag_to_remove_tiles (3361212377437088062) -->
- <skip />
+ <string name="drag_to_remove_tiles" msgid="3361212377437088062">"നീക്കംചെയ്യുന്നതിന് ഇവിടെ വലിച്ചിടുക"</string>
<string name="qs_edit" msgid="2232596095725105230">"എഡിറ്റുചെയ്യുക"</string>
<string name="tuner_time" msgid="6572217313285536011">"സമയം"</string>
<string-array name="clock_options">
@@ -560,4 +596,14 @@
<string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"മുകളിലേക്ക് നീക്കുക"</string>
<string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"ഇടത്തേക്ക് നീക്കുക"</string>
<string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"വലത്തേക്ക് നീക്കുക"</string>
+ <string name="forced_resizable_info_text" msgid="7591061837558867999">"മൾട്ടി-വിൻഡോയിൽ ആപ്പ് പ്രവർത്തിച്ചേക്കില്ല"</string>
+ <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"സ്ഥാനം <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>. എഡിറ്റുചെയ്യുന്നതിന് രണ്ടുതവണ ടാപ്പുചെയ്യുക."</string>
+ <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. ചേർക്കാൻ രണ്ടുതവണ ടാപ്പുചെയ്യുക."</string>
+ <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"സ്ഥാനം <xliff:g id="POSITION">%1$d</xliff:g>. തിരഞ്ഞെടുക്കാൻ രണ്ടുതവണ ടാപ്പുചെയ്യുക."</string>
+ <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"<xliff:g id="TILE_NAME">%1$s</xliff:g> നീക്കുക"</string>
+ <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"<xliff:g id="TILE_NAME">%1$s</xliff:g> നീക്കംചെയ്യുക"</string>
+ <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"സ്ഥാനം <xliff:g id="POSITION">%2$d</xliff:g>-ലേക്ക് <xliff:g id="TILE_NAME">%1$s</xliff:g> ചേർക്കുന്നു"</string>
+ <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"<xliff:g id="TILE_NAME">%1$s</xliff:g> നീക്കംചെയ്യുന്നു"</string>
+ <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"സ്ഥാനം <xliff:g id="POSITION">%2$d</xliff:g>-ലേക്ക് <xliff:g id="TILE_NAME">%1$s</xliff:g> നീക്കി"</string>
+ <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"ദ്രുത ക്രമീകരണ എഡിറ്റർ."</string>
</resources>
diff --git a/packages/SystemUI/res/values-ml-rIN/strings_tv.xml b/packages/SystemUI/res/values-ml-rIN/strings_tv.xml
index c054eed..09fe4ce 100644
--- a/packages/SystemUI/res/values-ml-rIN/strings_tv.xml
+++ b/packages/SystemUI/res/values-ml-rIN/strings_tv.xml
@@ -26,6 +26,5 @@
<string name="pip_hold_home" msgid="340086535668778109">"PIP നിയന്ത്രിക്കാൻ "<b>"ഹോം"</b>" പിടിക്കുക"</string>
<string name="pip_onboarding_description" msgid="2882896641362814195">"PIP നിയന്ത്രിക്കാൻ ഹോം ബട്ടൺ അമർത്തിപ്പിടിക്കുക"</string>
<string name="pip_onboarding_button" msgid="3957426748484904611">"മനസ്സിലായി"</string>
- <!-- no translation found for recents_tv_dismiss (3555093879593377731) -->
- <skip />
+ <string name="recents_tv_dismiss" msgid="3555093879593377731">"ഡിസ്മിസ് ചെയ്യുക"</string>
</resources>
diff --git a/packages/SystemUI/res/values-mn-rMN/strings.xml b/packages/SystemUI/res/values-mn-rMN/strings.xml
index b9ddad7..80cb8f2 100644
--- a/packages/SystemUI/res/values-mn-rMN/strings.xml
+++ b/packages/SystemUI/res/values-mn-rMN/strings.xml
@@ -166,6 +166,8 @@
<string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"<xliff:g id="APP">%s</xliff:g>-г хаах."</string>
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> байхгүй."</string>
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Хамгийн сүүлийн бүх програмыг арилгасан байна."</string>
+ <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+ <skip />
<string name="accessibility_recents_item_launched" msgid="7616039892382525203">"<xliff:g id="APP">%s</xliff:g>-г эхлүүлж байна."</string>
<string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
<string name="accessibility_notification_dismissed" msgid="854211387186306927">"Мэдэгдэл хаагдсан."</string>
@@ -234,8 +236,7 @@
<string name="gps_notification_found_text" msgid="4619274244146446464">"GPS байршил"</string>
<string name="accessibility_location_active" msgid="2427290146138169014">"Байршлын хүсэлтүүд идэвхтэй"</string>
<string name="accessibility_clear_all" msgid="5235938559247164925">"Бүх мэдэгдлийг цэвэрлэх."</string>
- <!-- no translation found for notification_group_overflow_indicator (1863231301642314183) -->
- <skip />
+ <string name="notification_group_overflow_indicator" msgid="1863231301642314183">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string>
<string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"Мэдэгдлийн тохиргоо"</string>
<string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"<xliff:g id="APP_NAME">%s</xliff:g> тохиргоо"</string>
<string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Дэлгэц автоматаар эргэнэ."</string>
@@ -308,8 +309,7 @@
<string name="recents_search_bar_label" msgid="8074997400187836677">"хайх"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g>-г эхлүүлж чадсангүй."</string>
<string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g>-г аюулгүй горимд идэвхгүй болгосон."</string>
- <string name="recents_history_button_label" msgid="5153358867807604821">"Түүх"</string>
- <string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Устгах"</string>
+ <string name="recents_stack_action_button_label" msgid="6593727103310426253">"Бүгдийг арилгах"</string>
<string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"Энэ апп олон цонхыг дэмждэггүй"</string>
<string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"Апп олон цонхыг дэмждэггүй"</string>
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Хэвтээ чиглэлд хуваах"</string>
@@ -478,8 +478,7 @@
<string name="notification_importance_max" msgid="5806278962376556491">"Мэдэгдлийг жагсаалтын эхэнд яаралтай дуутай харуулах"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Бусад тохиргоо"</string>
<string name="notification_done" msgid="5279426047273930175">"Дууссан"</string>
- <!-- no translation found for notification_gear_accessibility (94429150213089611) -->
- <skip />
+ <string name="notification_gear_accessibility" msgid="94429150213089611">"<xliff:g id="APP_NAME">%1$s</xliff:g> мэдэгдлийн хяналт"</string>
<string name="color_and_appearance" msgid="1254323855964993144">"Өнгө, харагдах байдал"</string>
<string name="night_mode" msgid="3540405868248625488">"Шөнийн горим"</string>
<string name="calibrate_display" msgid="5974642573432039217">"Дэлгэцийг тохируулах"</string>
@@ -499,10 +498,48 @@
<string name="battery_detail_charging_summary" msgid="1279095653533044008">"Цэнэглэх үед тэжээл хэмнэгч ажиллахгүй"</string>
<string name="battery_detail_switch_title" msgid="6285872470260795421">"Тэжээл хэмнэгч"</string>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"Гүйцэтгэл болон дэвсгэрийн датаг багасгадаг"</string>
+ <string name="keyboard_key_button_template" msgid="6230056639734377300">"<xliff:g id="NAME">%1$s</xliff:g> товчлуур"</string>
+ <string name="keyboard_key_home" msgid="2243500072071305073">"Нүүр хуудас"</string>
+ <string name="keyboard_key_back" msgid="2337450286042721351">"Буцах"</string>
+ <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"Дээш"</string>
+ <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"Доош"</string>
+ <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"Зүүн"</string>
+ <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"Баруун"</string>
+ <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"Гол хэсэг"</string>
+ <string name="keyboard_key_tab" msgid="3871485650463164476">"Чихтэй хуудас"</string>
+ <string name="keyboard_key_space" msgid="2499861316311153293">"Зай"</string>
+ <string name="keyboard_key_enter" msgid="5739632123216118137">"Оруулах"</string>
+ <string name="keyboard_key_backspace" msgid="1559580097512385854">"Арилгах"</string>
+ <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"Тоглуулах/Түр зогсоох"</string>
+ <string name="keyboard_key_media_stop" msgid="2859963958595908962">"Зогсоох"</string>
+ <string name="keyboard_key_media_next" msgid="1894394911630345607">"Дараах"</string>
+ <string name="keyboard_key_media_previous" msgid="4256072387192967261">"Өмнөх"</string>
+ <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"Буцааж хураах"</string>
+ <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"Хурдан урагшлуулах"</string>
+ <string name="keyboard_key_page_up" msgid="5654098530106845603">"Хуудас дээш"</string>
+ <string name="keyboard_key_page_down" msgid="8720502083731906136">"Хуудас доош"</string>
+ <string name="keyboard_key_forward_del" msgid="1391451334716490176">"Устгах"</string>
+ <string name="keyboard_key_move_home" msgid="2765693292069487486">"Нүүр хуудас"</string>
+ <string name="keyboard_key_move_end" msgid="5901174332047975247">"Төгсгөл"</string>
+ <string name="keyboard_key_insert" msgid="8530501581636082614">"Оруулах"</string>
+ <string name="keyboard_key_num_lock" msgid="5052537581246772117">"Тоо бичих горим"</string>
+ <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"Тоо бичих товчлуур <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"Систем"</string>
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Нүүр хуудас"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Саяхны"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Буцах"</string>
+ <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Мэдэгдэл"</string>
+ <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"Гарын товчлол"</string>
+ <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"Оролтын аргыг солих"</string>
+ <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"Апп"</string>
+ <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"Дэмжлэг"</string>
+ <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"Хөтөч"</string>
+ <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"Харилцагчид"</string>
+ <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"Имэйл"</string>
+ <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"IM"</string>
+ <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"Хөгжим"</string>
+ <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+ <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"Хуанли"</string>
<string name="tuner_full_zen_title" msgid="4540823317772234308">"Түвшний хяналттай харуулах"</string>
<string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Бүү саад бол"</string>
<string name="volume_dnd_silent" msgid="4363882330723050727">"Түвшний товчлуурын товчлол"</string>
@@ -557,4 +594,14 @@
<string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Дээш зөөх"</string>
<string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Зүүн тийш зөөх"</string>
<string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Баруун тийш зөөх"</string>
+ <string name="forced_resizable_info_text" msgid="7591061837558867999">"Олон цонхтой үед апп ажиллахгүй байж болзошгүй"</string>
+ <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"Байршил <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>. Засахын тулд 2 удаа дарна уу."</string>
+ <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. Нэмэхийн тулд 2 удаа дарна уу."</string>
+ <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"Албан тушаал <xliff:g id="POSITION">%1$d</xliff:g>. Сонгохын тулд 2 удаа дарна уу."</string>
+ <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"<xliff:g id="TILE_NAME">%1$s</xliff:g>-г зөөх"</string>
+ <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"<xliff:g id="TILE_NAME">%1$s</xliff:g>-г устгах"</string>
+ <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="TILE_NAME">%1$s</xliff:g>-г <xliff:g id="POSITION">%2$d</xliff:g> байршилд нэмсэн"</string>
+ <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"<xliff:g id="TILE_NAME">%1$s</xliff:g>-г устгасан"</string>
+ <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="TILE_NAME">%1$s</xliff:g>-г <xliff:g id="POSITION">%2$d</xliff:g> байршилд зөөсөн"</string>
+ <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Түргэн тохиргоо засварлагч."</string>
</resources>
diff --git a/packages/SystemUI/res/values-mn-rMN/strings_tv.xml b/packages/SystemUI/res/values-mn-rMN/strings_tv.xml
index 54f2282..ca522d3 100644
--- a/packages/SystemUI/res/values-mn-rMN/strings_tv.xml
+++ b/packages/SystemUI/res/values-mn-rMN/strings_tv.xml
@@ -26,6 +26,5 @@
<string name="pip_hold_home" msgid="340086535668778109">"PIP-г удирдахын тулд "<b>"HOME"</b>" товчлуурыг дарна уу"</string>
<string name="pip_onboarding_description" msgid="2882896641362814195">"PIP-г удирдахын тулд НҮҮР ХУУДАС товчлуурыг дараад хүлээнэ үү"</string>
<string name="pip_onboarding_button" msgid="3957426748484904611">"Ойлголоо"</string>
- <!-- no translation found for recents_tv_dismiss (3555093879593377731) -->
- <skip />
+ <string name="recents_tv_dismiss" msgid="3555093879593377731">"Хаах"</string>
</resources>
diff --git a/packages/SystemUI/res/values-mr-rIN/strings.xml b/packages/SystemUI/res/values-mr-rIN/strings.xml
index e65897c..76dfcd5 100644
--- a/packages/SystemUI/res/values-mr-rIN/strings.xml
+++ b/packages/SystemUI/res/values-mr-rIN/strings.xml
@@ -168,6 +168,8 @@
<string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"<xliff:g id="APP">%s</xliff:g> डिसमिस करा."</string>
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> डिसमिस केला."</string>
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"अलीकडील सर्व अनुप्रयोग डिसमिस झाले."</string>
+ <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+ <skip />
<string name="accessibility_recents_item_launched" msgid="7616039892382525203">"<xliff:g id="APP">%s</xliff:g> प्रारंभ करीत आहे."</string>
<string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
<string name="accessibility_notification_dismissed" msgid="854211387186306927">"सूचना डिसमिस केल्या."</string>
@@ -236,8 +238,7 @@
<string name="gps_notification_found_text" msgid="4619274244146446464">"GPS द्वारे स्थान सेट केले"</string>
<string name="accessibility_location_active" msgid="2427290146138169014">"स्थान विनंत्या सक्रिय"</string>
<string name="accessibility_clear_all" msgid="5235938559247164925">"सर्व सूचना साफ करा."</string>
- <!-- no translation found for notification_group_overflow_indicator (1863231301642314183) -->
- <skip />
+ <string name="notification_group_overflow_indicator" msgid="1863231301642314183">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string>
<string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"सूचना सेटिंग्ज"</string>
<string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"<xliff:g id="APP_NAME">%s</xliff:g> सेटिंग्ज"</string>
<string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"स्क्रीन स्वयंचलितपणे फिरेल."</string>
@@ -310,8 +311,7 @@
<string name="recents_search_bar_label" msgid="8074997400187836677">"शोधा"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g> प्रारंभ करणे शक्य झाले नाही."</string>
<string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g> सुरक्षित-मोडमध्ये अक्षम केला आहे."</string>
- <string name="recents_history_button_label" msgid="5153358867807604821">"इतिहास"</string>
- <string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"साफ करा"</string>
+ <string name="recents_stack_action_button_label" msgid="6593727103310426253">"सर्व साफ करा"</string>
<string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"हा अॅप एकाधिक-विंडोला समर्थन देत नाही"</string>
<string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"अॅप एकाधिक-विंडोला समर्थन देत नाही"</string>
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"क्षैतिज विभाजित करा"</string>
@@ -480,8 +480,7 @@
<string name="notification_importance_max" msgid="5806278962376556491">"सूचनांच्या शीर्षस्थानी दर्शवा, स्क्रीनवर पहा आणि ध्वनीस अनुमती द्या"</string>
<string name="notification_more_settings" msgid="816306283396553571">"अधिक सेटिंग्ज"</string>
<string name="notification_done" msgid="5279426047273930175">"पूर्ण झाले"</string>
- <!-- no translation found for notification_gear_accessibility (94429150213089611) -->
- <skip />
+ <string name="notification_gear_accessibility" msgid="94429150213089611">"<xliff:g id="APP_NAME">%1$s</xliff:g> सूचना नियंत्रणे"</string>
<string name="color_and_appearance" msgid="1254323855964993144">"रंग आणि स्वरूप"</string>
<string name="night_mode" msgid="3540405868248625488">"रात्र मोड"</string>
<string name="calibrate_display" msgid="5974642573432039217">"प्रदर्शनाचे मापन करा"</string>
@@ -501,10 +500,48 @@
<string name="battery_detail_charging_summary" msgid="1279095653533044008">"चार्ज करताना बॅटरी बचतकर्ता उपलब्ध नाही"</string>
<string name="battery_detail_switch_title" msgid="6285872470260795421">"बॅटरी बचतकर्ता"</string>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"कार्यप्रदर्शन आणि पार्श्वभूमी डेटा कमी करते"</string>
+ <string name="keyboard_key_button_template" msgid="6230056639734377300">"बटण <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="keyboard_key_home" msgid="2243500072071305073">"Home"</string>
+ <string name="keyboard_key_back" msgid="2337450286042721351">"परत"</string>
+ <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"वर"</string>
+ <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"खाली"</string>
+ <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"डावा"</string>
+ <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"उजवा"</string>
+ <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"मध्यवर्ती"</string>
+ <string name="keyboard_key_tab" msgid="3871485650463164476">"टॅब"</string>
+ <string name="keyboard_key_space" msgid="2499861316311153293">"Space"</string>
+ <string name="keyboard_key_enter" msgid="5739632123216118137">"Enter"</string>
+ <string name="keyboard_key_backspace" msgid="1559580097512385854">"Backspace"</string>
+ <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"प्ले करा/विराम द्या"</string>
+ <string name="keyboard_key_media_stop" msgid="2859963958595908962">"थांबा"</string>
+ <string name="keyboard_key_media_next" msgid="1894394911630345607">"पुढील"</string>
+ <string name="keyboard_key_media_previous" msgid="4256072387192967261">"मागील"</string>
+ <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"मागे न्या"</string>
+ <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"पुढे करा"</string>
+ <string name="keyboard_key_page_up" msgid="5654098530106845603">"Page Up"</string>
+ <string name="keyboard_key_page_down" msgid="8720502083731906136">"Page Down"</string>
+ <string name="keyboard_key_forward_del" msgid="1391451334716490176">"हटवा"</string>
+ <string name="keyboard_key_move_home" msgid="2765693292069487486">"Home"</string>
+ <string name="keyboard_key_move_end" msgid="5901174332047975247">"End"</string>
+ <string name="keyboard_key_insert" msgid="8530501581636082614">"घाला"</string>
+ <string name="keyboard_key_num_lock" msgid="5052537581246772117">"Num Lock"</string>
+ <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"Numpad <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"सिस्टीम"</string>
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"मुख्यपृष्ठ"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"अलीकडील"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"परत"</string>
+ <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"सूचना"</string>
+ <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"कीबोर्ड शॉर्टकट"</string>
+ <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"इनपुट पद्धत स्विच करा"</string>
+ <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"अनुप्रयोग"</string>
+ <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"सहाय्य"</string>
+ <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"ब्राउझर"</string>
+ <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"संपर्क"</string>
+ <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"ईमेल"</string>
+ <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"IM"</string>
+ <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"संगीत"</string>
+ <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+ <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"कॅलेंडर"</string>
<string name="tuner_full_zen_title" msgid="4540823317772234308">"आवाज नियंत्रणांसह दर्शवा"</string>
<string name="volume_and_do_not_disturb" msgid="3373784330208603030">"व्यत्यय आणू नका"</string>
<string name="volume_dnd_silent" msgid="4363882330723050727">"आवाजाच्या बटणांचा शार्टकट"</string>
@@ -540,8 +577,7 @@
<string name="select_keycode" msgid="7413765103381924584">"कीबोर्ड बटण निवडा"</string>
<string name="preview" msgid="9077832302472282938">"पूर्वावलोकन"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"टाइल जोडण्यासाठी ड्रॅग करा"</string>
- <!-- no translation found for drag_to_remove_tiles (3361212377437088062) -->
- <skip />
+ <string name="drag_to_remove_tiles" msgid="3361212377437088062">"काढण्यासाठी येथे ड्रॅग करा"</string>
<string name="qs_edit" msgid="2232596095725105230">"संपादित करा"</string>
<string name="tuner_time" msgid="6572217313285536011">"वेळ"</string>
<string-array name="clock_options">
@@ -560,4 +596,14 @@
<string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"वर हलवा"</string>
<string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"डावीकडे हलवा"</string>
<string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"उजवीकडे हलवा"</string>
+ <string name="forced_resizable_info_text" msgid="7591061837558867999">"एकाधिक-विंडो सह अॅप कार्य करू शकत नाही"</string>
+ <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"स्थिती <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>. संपादित करण्यासाठी दोनदा टॅप करा."</string>
+ <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g> . जोडण्यासाठी दोनदा टॅप करा."</string>
+ <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"स्थिती <xliff:g id="POSITION">%1$d</xliff:g>. निवडण्यासाठी दोनदा टॅप करा."</string>
+ <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"<xliff:g id="TILE_NAME">%1$s</xliff:g> हलवा"</string>
+ <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"<xliff:g id="TILE_NAME">%1$s</xliff:g> काढा"</string>
+ <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="TILE_NAME">%1$s</xliff:g> ला <xliff:g id="POSITION">%2$d</xliff:g> स्थितीवर जोडले आहे"</string>
+ <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"<xliff:g id="TILE_NAME">%1$s</xliff:g> ला काढले आहे"</string>
+ <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="TILE_NAME">%1$s</xliff:g> ला <xliff:g id="POSITION">%2$d</xliff:g> स्थितीवर हलविले"</string>
+ <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"द्रुत सेटिंग्ज संपादक."</string>
</resources>
diff --git a/packages/SystemUI/res/values-mr-rIN/strings_tv.xml b/packages/SystemUI/res/values-mr-rIN/strings_tv.xml
index 6a29867..318e3e9 100644
--- a/packages/SystemUI/res/values-mr-rIN/strings_tv.xml
+++ b/packages/SystemUI/res/values-mr-rIN/strings_tv.xml
@@ -26,6 +26,5 @@
<string name="pip_hold_home" msgid="340086535668778109">"PIP नियंत्रित करण्यासाठी "<b>"मुख्यपृष्ठ"</b>" धरून ठेवा"</string>
<string name="pip_onboarding_description" msgid="2882896641362814195">"PIP नियंत्रित करण्यासाठी मुख्यपृष्ठ बटण दाबा आणि धरून ठेवा"</string>
<string name="pip_onboarding_button" msgid="3957426748484904611">"समजले"</string>
- <!-- no translation found for recents_tv_dismiss (3555093879593377731) -->
- <skip />
+ <string name="recents_tv_dismiss" msgid="3555093879593377731">"डिसमिस करा"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ms-rMY/strings.xml b/packages/SystemUI/res/values-ms-rMY/strings.xml
index 432110c..9401198 100644
--- a/packages/SystemUI/res/values-ms-rMY/strings.xml
+++ b/packages/SystemUI/res/values-ms-rMY/strings.xml
@@ -168,6 +168,8 @@
<string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Ketepikan <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> ditolak."</string>
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Semua aplikasi terbaharu diketepikan."</string>
+ <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+ <skip />
<string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Memulakan <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
<string name="accessibility_notification_dismissed" msgid="854211387186306927">"Pemberitahuan diketepikan."</string>
@@ -236,8 +238,7 @@
<string name="gps_notification_found_text" msgid="4619274244146446464">"Lokasi ditetapkan oleh GPS"</string>
<string name="accessibility_location_active" msgid="2427290146138169014">"Permintaan lokasi aktif"</string>
<string name="accessibility_clear_all" msgid="5235938559247164925">"Padamkan semua pemberitahuan."</string>
- <!-- no translation found for notification_group_overflow_indicator (1863231301642314183) -->
- <skip />
+ <string name="notification_group_overflow_indicator" msgid="1863231301642314183">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string>
<string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"Tetapan pemberitahuan"</string>
<string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"<xliff:g id="APP_NAME">%s</xliff:g> tetapan"</string>
<string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Skrin akan berputar secara automatik."</string>
@@ -310,8 +311,7 @@
<string name="recents_search_bar_label" msgid="8074997400187836677">"cari"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"Tidak dapat memulakan <xliff:g id="APP">%s</xliff:g>."</string>
<string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g> dilumpuhkan dalam mod selamat."</string>
- <string name="recents_history_button_label" msgid="5153358867807604821">"Sejarah"</string>
- <string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Kosongkan"</string>
+ <string name="recents_stack_action_button_label" msgid="6593727103310426253">"Kosongkan semua"</string>
<string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"Apl ini tidak menyokong berbilang tetingkap"</string>
<string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"Apl tidak menyokong berbilang tetingkap"</string>
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Mendatar Terpisah"</string>
@@ -480,8 +480,7 @@
<string name="notification_importance_max" msgid="5806278962376556491">"Tunjukkan pada bahagian atas senarai pemberitahuan, intai pada skrin dan benarkan bunyi"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Lagi tetapan"</string>
<string name="notification_done" msgid="5279426047273930175">"Selesai"</string>
- <!-- no translation found for notification_gear_accessibility (94429150213089611) -->
- <skip />
+ <string name="notification_gear_accessibility" msgid="94429150213089611">"Kawalan pemberitahuan <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="color_and_appearance" msgid="1254323855964993144">"Warna dan penampilan"</string>
<string name="night_mode" msgid="3540405868248625488">"Mod malam"</string>
<string name="calibrate_display" msgid="5974642573432039217">"Tentukur paparan"</string>
@@ -501,10 +500,48 @@
<string name="battery_detail_charging_summary" msgid="1279095653533044008">"Penjimat Bateri tidak tersedia semasa mengecas"</string>
<string name="battery_detail_switch_title" msgid="6285872470260795421">"Penjimat Bateri"</string>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"Mengurangkan prestasi dan data latar belakang"</string>
+ <string name="keyboard_key_button_template" msgid="6230056639734377300">"Butang <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="keyboard_key_home" msgid="2243500072071305073">"Skrin Utama"</string>
+ <string name="keyboard_key_back" msgid="2337450286042721351">"Kembali"</string>
+ <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"Ke atas"</string>
+ <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"Ke bawah"</string>
+ <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"Ke kiri"</string>
+ <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"Ke kanan"</string>
+ <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"Tengah"</string>
+ <string name="keyboard_key_tab" msgid="3871485650463164476">"Tab"</string>
+ <string name="keyboard_key_space" msgid="2499861316311153293">"Space"</string>
+ <string name="keyboard_key_enter" msgid="5739632123216118137">"Enter"</string>
+ <string name="keyboard_key_backspace" msgid="1559580097512385854">"Undur ruang"</string>
+ <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"Main/Jeda"</string>
+ <string name="keyboard_key_media_stop" msgid="2859963958595908962">"Berhenti"</string>
+ <string name="keyboard_key_media_next" msgid="1894394911630345607">"Seterusnya"</string>
+ <string name="keyboard_key_media_previous" msgid="4256072387192967261">"Sebelumnya"</string>
+ <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"Mandir"</string>
+ <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"Mara Laju"</string>
+ <string name="keyboard_key_page_up" msgid="5654098530106845603">"Page Up"</string>
+ <string name="keyboard_key_page_down" msgid="8720502083731906136">"Page Down"</string>
+ <string name="keyboard_key_forward_del" msgid="1391451334716490176">"Delete"</string>
+ <string name="keyboard_key_move_home" msgid="2765693292069487486">"Home"</string>
+ <string name="keyboard_key_move_end" msgid="5901174332047975247">"End"</string>
+ <string name="keyboard_key_insert" msgid="8530501581636082614">"Insert"</string>
+ <string name="keyboard_key_num_lock" msgid="5052537581246772117">"Num Lock"</string>
+ <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"Pad nombor <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"Sistem"</string>
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Skrin Utama"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Terbaharu"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Kembali"</string>
+ <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Pemberitahuan"</string>
+ <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"Pintasan Papan Kekunci"</string>
+ <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"Tukar kaedah input"</string>
+ <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"Aplikasi"</string>
+ <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"Bantu"</string>
+ <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"Penyemak imbas"</string>
+ <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"Kenalan"</string>
+ <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"E-mel"</string>
+ <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"IM"</string>
+ <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"Muzik"</string>
+ <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+ <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"Kalendar"</string>
<string name="tuner_full_zen_title" msgid="4540823317772234308">"Tunjukkan dengan kawalan kelantangan"</string>
<string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Jangan ganggu"</string>
<string name="volume_dnd_silent" msgid="4363882330723050727">"Pintasan butang kelantangan"</string>
@@ -559,4 +596,14 @@
<string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Alih ke atas"</string>
<string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Alih ke kiri"</string>
<string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Alih ke kanan"</string>
+ <string name="forced_resizable_info_text" msgid="7591061837558867999">"Apl mungkin tidak berfungsi dengan berbilang tetingkap"</string>
+ <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"Kedudukan <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>. Dwiketik untuk mengedit."</string>
+ <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. Dwiketik untuk menambah."</string>
+ <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"Kedudukan <xliff:g id="POSITION">%1$d</xliff:g>. Dwiketik untuk memilih."</string>
+ <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"Alihkan <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"Alih keluar <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="TILE_NAME">%1$s</xliff:g> ditambahkan pada kedudukan <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+ <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"<xliff:g id="TILE_NAME">%1$s</xliff:g> dialih keluar"</string>
+ <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="TILE_NAME">%1$s</xliff:g> dialihkan ke kedudukan <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+ <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Editor tetapan pantas."</string>
</resources>
diff --git a/packages/SystemUI/res/values-ms-rMY/strings_tv.xml b/packages/SystemUI/res/values-ms-rMY/strings_tv.xml
index d358cc0..eb5af9e3 100644
--- a/packages/SystemUI/res/values-ms-rMY/strings_tv.xml
+++ b/packages/SystemUI/res/values-ms-rMY/strings_tv.xml
@@ -26,6 +26,5 @@
<string name="pip_hold_home" msgid="340086535668778109">"Thn "<b>"SKRN UTMA"</b>" utk kwl PIP"</string>
<string name="pip_onboarding_description" msgid="2882896641362814195">"Tekan dan tahan butang SKRIN UTAMA untuk mengawal PIP"</string>
<string name="pip_onboarding_button" msgid="3957426748484904611">"OK"</string>
- <!-- no translation found for recents_tv_dismiss (3555093879593377731) -->
- <skip />
+ <string name="recents_tv_dismiss" msgid="3555093879593377731">"Ketepikan"</string>
</resources>
diff --git a/packages/SystemUI/res/values-my-rMM/strings.xml b/packages/SystemUI/res/values-my-rMM/strings.xml
index 8994499..6964750 100644
--- a/packages/SystemUI/res/values-my-rMM/strings.xml
+++ b/packages/SystemUI/res/values-my-rMM/strings.xml
@@ -168,6 +168,8 @@
<string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"<xliff:g id="APP">%s</xliff:g>ကို ပယ်လိုက်ရန်"</string>
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> ထုတ်ထားသည်။"</string>
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"မကြာသေးမီက အပလီကေးရှင်းများအားလုံး ဖယ်ထုတ်ပြီးပါပြီ။"</string>
+ <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+ <skip />
<string name="accessibility_recents_item_launched" msgid="7616039892382525203">"<xliff:g id="APP">%s</xliff:g>ကို စတင်နေသည်။"</string>
<string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g><xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
<string name="accessibility_notification_dismissed" msgid="854211387186306927">"အကြောင်းကြားချက်ကိုဖယ်ရှားပြီး"</string>
@@ -309,8 +311,7 @@
<string name="recents_search_bar_label" msgid="8074997400187836677">"ရှာဖွေရန်"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g> ကို မစနိုင်ပါ။"</string>
<string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g> ကို ဘေးကင်းလုံခြုံသည့်မုဒ်တွင် ပိတ်ထားပါသည်။"</string>
- <string name="recents_history_button_label" msgid="5153358867807604821">"မှတ်တမ်း"</string>
- <string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"ရှင်းလင်းပါ"</string>
+ <string name="recents_stack_action_button_label" msgid="6593727103310426253">"အားလုံး ရှင်းလင်းပါ"</string>
<string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"ဤအက်ပ်သည် ဝင်းဒိုးများစွာဖွင့်ခြင်းကို ပံ့ပိုးမထားပါ"</string>
<string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"အက်ပ်သည် ဝင်းဒိုးများစွာဖွင့်ခြင်းကို ပံ့ပိုးမထားပါ"</string>
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"ရေပြင်ညီ ပိုင်းမည်"</string>
@@ -499,10 +500,48 @@
<string name="battery_detail_charging_summary" msgid="1279095653533044008">"အားသွင်းနေချိန်မှာ Battery Saver ကို သုံးမရပါ"</string>
<string name="battery_detail_switch_title" msgid="6285872470260795421">"Battery Saver"</string>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"လုပ်ဆောင်မှု နှင့် နောက်ခံ ဒေတာကို လျော့နည်းစေပါသည်"</string>
+ <string name="keyboard_key_button_template" msgid="6230056639734377300">"ခလုတ် <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="keyboard_key_home" msgid="2243500072071305073">"ပင်မ"</string>
+ <string name="keyboard_key_back" msgid="2337450286042721351">"နောက်သို့"</string>
+ <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"အပေါ်"</string>
+ <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"အောက်"</string>
+ <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"ဘယ်"</string>
+ <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"ညာ"</string>
+ <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"ဌာန"</string>
+ <string name="keyboard_key_tab" msgid="3871485650463164476">"တဘ်"</string>
+ <string name="keyboard_key_space" msgid="2499861316311153293">"နေရာခြားပါ"</string>
+ <string name="keyboard_key_enter" msgid="5739632123216118137">"Enter ခလုတ်"</string>
+ <string name="keyboard_key_backspace" msgid="1559580097512385854">"နောက်ပြန်ဖျက်ပါ"</string>
+ <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"ဖွင့်ပါ/ခဏရပ်ပါ"</string>
+ <string name="keyboard_key_media_stop" msgid="2859963958595908962">"ရပ်ပါ"</string>
+ <string name="keyboard_key_media_next" msgid="1894394911630345607">"ရှေ့သို့"</string>
+ <string name="keyboard_key_media_previous" msgid="4256072387192967261">"ယခင်"</string>
+ <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"နောက်သို့ရစ်ပါ"</string>
+ <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"ရှေ့သို့ရစ်ပါ"</string>
+ <string name="keyboard_key_page_up" msgid="5654098530106845603">"အပေါ်စာမျက်နှာသို့သွားပါ"</string>
+ <string name="keyboard_key_page_down" msgid="8720502083731906136">"အောက်စာမျက်နှာသို့သွားပါ"</string>
+ <string name="keyboard_key_forward_del" msgid="1391451334716490176">"ဖျက်ပါ"</string>
+ <string name="keyboard_key_move_home" msgid="2765693292069487486">"ပင်မ"</string>
+ <string name="keyboard_key_move_end" msgid="5901174332047975247">"ပြီးပါပြီ"</string>
+ <string name="keyboard_key_insert" msgid="8530501581636082614">"ထည့်ပါ"</string>
+ <string name="keyboard_key_num_lock" msgid="5052537581246772117">"Num Lock"</string>
+ <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"ဂဏန်းကွက်<xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"စနစ်"</string>
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"ပင်မ"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"မကြာသေးခင်က"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"နောက်သို့"</string>
+ <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"အကြောင်းကြားချက်များ"</string>
+ <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"ကီးဘုတ် ဖြတ်လမ်းများ"</string>
+ <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"ထည့်သွင်းမှုနည်းလမ်းကို ပြောင်းလဲပါ"</string>
+ <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"အက်ပ်များ"</string>
+ <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"အထောက်အကူ"</string>
+ <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"ဘရောင်ဇာ"</string>
+ <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"အဆက်အသွယ်များ"</string>
+ <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"အီးမေးလ်"</string>
+ <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"အမြန်စာတိုစနစ်"</string>
+ <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"Music"</string>
+ <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+ <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"ပြက္ခဒိန်"</string>
<string name="tuner_full_zen_title" msgid="4540823317772234308">"အသံထိန်းချုပ်သည့်ခလုတ်များဖြင့် ပြပါ"</string>
<string name="volume_and_do_not_disturb" msgid="3373784330208603030">"မနှောက်ယှက်ပါနှင့်"</string>
<string name="volume_dnd_silent" msgid="4363882330723050727">"အသံထိန်းချုပ်သည့်ခလုတ် ဖြတ်လမ်း"</string>
@@ -557,4 +596,14 @@
<string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"အပေါ်သို့ရွှေ့ပါ"</string>
<string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"ဘယ်ဘက်သို့ရွှေ့ပါ"</string>
<string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"ညာဘက်သို့ရွှေ့ပါ"</string>
+ <string name="forced_resizable_info_text" msgid="7591061837558867999">"အက်ပ်သည် ဝင်းဒိုးများတပြိုင်နက်ဖွင့်ခြင်းကို မပံ့ပိုးပါ"</string>
+ <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"<xliff:g id="POSITION">%1$d</xliff:g>၊ <xliff:g id="TILE_NAME">%2$s</xliff:g> နေရာ။ တည်းဖြတ်ရန် နှစ်ချက်တို့ပါ။"</string>
+ <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>။ ပေါင်းထည့်ရန် နှစ်ချက်တို့ပါ။"</string>
+ <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"<xliff:g id="POSITION">%1$d</xliff:g> နေရာ။ ရွေးချယ်ရန် နှစ်ချက်တို့ပါ။"</string>
+ <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"<xliff:g id="TILE_NAME">%1$s</xliff:g> ကိုရွှေ့ပါ"</string>
+ <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"<xliff:g id="TILE_NAME">%1$s</xliff:g> ကိုဖယ်ရှားပါ"</string>
+ <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="TILE_NAME">%1$s</xliff:g> ကို <xliff:g id="POSITION">%2$d</xliff:g> နေရာသို့ ပေါင်းထည့်ထားပါသည်"</string>
+ <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"<xliff:g id="TILE_NAME">%1$s</xliff:g> ကိုဖယ်ရှားလိုက်ပါပြီ"</string>
+ <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="TILE_NAME">%1$s</xliff:g> ကို <xliff:g id="POSITION">%2$d</xliff:g> နေရာသို့ ရွှေ့လိုက်ပါပြီ"</string>
+ <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"မြန်ဆန်သည့် ဆက်တင်တည်းဖြတ်စနစ်"</string>
</resources>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index 9ee29ab..220250b 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -168,6 +168,8 @@
<string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Avvis <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> avvist."</string>
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Alle nylig brukte apper er avvist."</string>
+ <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+ <skip />
<string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Starter <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
<string name="accessibility_notification_dismissed" msgid="854211387186306927">"Varselet ble skjult."</string>
@@ -309,8 +311,7 @@
<string name="recents_search_bar_label" msgid="8074997400187836677">"Søk"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"Kunne ikke starte <xliff:g id="APP">%s</xliff:g>."</string>
<string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g> er slått av i sikker modus."</string>
- <string name="recents_history_button_label" msgid="5153358867807604821">"Logg"</string>
- <string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Tøm"</string>
+ <string name="recents_stack_action_button_label" msgid="6593727103310426253">"Tøm alt"</string>
<string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"Denne appen har ikke støtte for flervindusmodus"</string>
<string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"Appen har ikke støtte for flervindusmodus"</string>
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Del horisontalt"</string>
@@ -499,10 +500,48 @@
<string name="battery_detail_charging_summary" msgid="1279095653533044008">"Batterisparing er ikke tilgjengelig under lading"</string>
<string name="battery_detail_switch_title" msgid="6285872470260795421">"Batterisparing"</string>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"Reduserer ytelsen og begrenser bakgrunnsdataene"</string>
+ <string name="keyboard_key_button_template" msgid="6230056639734377300">"<xliff:g id="NAME">%1$s</xliff:g>-knappen"</string>
+ <string name="keyboard_key_home" msgid="2243500072071305073">"Startskjerm"</string>
+ <string name="keyboard_key_back" msgid="2337450286042721351">"Tilbake"</string>
+ <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"Opp"</string>
+ <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"Ned"</string>
+ <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"Venstre"</string>
+ <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"Høyre"</string>
+ <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"Midttasten"</string>
+ <string name="keyboard_key_tab" msgid="3871485650463164476">"Tab"</string>
+ <string name="keyboard_key_space" msgid="2499861316311153293">"Mellomrom"</string>
+ <string name="keyboard_key_enter" msgid="5739632123216118137">"Enter"</string>
+ <string name="keyboard_key_backspace" msgid="1559580097512385854">"Tilbaketasten"</string>
+ <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"Spill av / sett på pause"</string>
+ <string name="keyboard_key_media_stop" msgid="2859963958595908962">"Stopp"</string>
+ <string name="keyboard_key_media_next" msgid="1894394911630345607">"Neste"</string>
+ <string name="keyboard_key_media_previous" msgid="4256072387192967261">"Forrige"</string>
+ <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"Spol tilbake"</string>
+ <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"Spol fremover"</string>
+ <string name="keyboard_key_page_up" msgid="5654098530106845603">"Page Up"</string>
+ <string name="keyboard_key_page_down" msgid="8720502083731906136">"Page Down"</string>
+ <string name="keyboard_key_forward_del" msgid="1391451334716490176">"Delete"</string>
+ <string name="keyboard_key_move_home" msgid="2765693292069487486">"Startskjerm"</string>
+ <string name="keyboard_key_move_end" msgid="5901174332047975247">"End"</string>
+ <string name="keyboard_key_insert" msgid="8530501581636082614">"Insert"</string>
+ <string name="keyboard_key_num_lock" msgid="5052537581246772117">"Num Lock"</string>
+ <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"<xliff:g id="NAME">%1$s</xliff:g> på talltastaturet"</string>
<string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"System"</string>
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Startside"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Nylige"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Tilbake"</string>
+ <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Varsler"</string>
+ <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"Hurtigtaster"</string>
+ <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"Bytt inndatametode"</string>
+ <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"Apper"</string>
+ <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"Assist"</string>
+ <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"Nettleser"</string>
+ <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"Kontakter"</string>
+ <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"E-post"</string>
+ <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"Chat"</string>
+ <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"Musikk"</string>
+ <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+ <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"Kalender"</string>
<string name="tuner_full_zen_title" msgid="4540823317772234308">"Vis med volumkontrollene"</string>
<string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Ikke forstyrr"</string>
<string name="volume_dnd_silent" msgid="4363882330723050727">"Hurtigtast for volumknappene"</string>
@@ -557,4 +596,14 @@
<string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Flytt opp"</string>
<string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Flytt mot venstre"</string>
<string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Flytt mot høyre"</string>
+ <string name="forced_resizable_info_text" msgid="7591061837558867999">"Appen fungerer kanskje ikke i Flervindusmodus"</string>
+ <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"Plassering <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>. Dobbelttrykk for å endre."</string>
+ <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. Dobbelttrykk for å legge til."</string>
+ <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"Plassering <xliff:g id="POSITION">%1$d</xliff:g>. Dobbelttrykk for å velge."</string>
+ <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"Flytt <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"Fjern <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="TILE_NAME">%1$s</xliff:g> er lagt til i plassering <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+ <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"<xliff:g id="TILE_NAME">%1$s</xliff:g> er fjernet"</string>
+ <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="TILE_NAME">%1$s</xliff:g> er flyttet til plassering <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+ <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Redigeringsvindu for hurtiginnstillinger."</string>
</resources>
diff --git a/packages/SystemUI/res/values-ne-rNP/strings.xml b/packages/SystemUI/res/values-ne-rNP/strings.xml
index 5b139d1..836dc4b 100644
--- a/packages/SystemUI/res/values-ne-rNP/strings.xml
+++ b/packages/SystemUI/res/values-ne-rNP/strings.xml
@@ -168,6 +168,8 @@
<string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"<xliff:g id="APP">%s</xliff:g> खारेज गर्नुहोस्।"</string>
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> खारेज गरिएको छ।"</string>
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"सबै हालका अनुप्रयोगहरू खारेज गरियो।"</string>
+ <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+ <skip />
<string name="accessibility_recents_item_launched" msgid="7616039892382525203">"<xliff:g id="APP">%s</xliff:g>सुरु गर्दै।"</string>
<string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
<string name="accessibility_notification_dismissed" msgid="854211387186306927">"सूचना खारेज।"</string>
@@ -236,8 +238,7 @@
<string name="gps_notification_found_text" msgid="4619274244146446464">"GPS द्वारा स्थान सेट गरिएको"</string>
<string name="accessibility_location_active" msgid="2427290146138169014">"स्थान अनुरोधहरू सक्रिय"</string>
<string name="accessibility_clear_all" msgid="5235938559247164925">"सबै सूचनाहरू हटाउनुहोस्।"</string>
- <!-- no translation found for notification_group_overflow_indicator (1863231301642314183) -->
- <skip />
+ <string name="notification_group_overflow_indicator" msgid="1863231301642314183">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string>
<string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"अधिसूचना सेटिङ्हरू"</string>
<string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"<xliff:g id="APP_NAME">%s</xliff:g> सेटिङ्हरू"</string>
<string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"स्क्रिन स्वतः घुम्ने छ।"</string>
@@ -310,8 +311,7 @@
<string name="recents_search_bar_label" msgid="8074997400187836677">"खोजी गर्नुहोस्"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"सुरु गर्न सकिएन <xliff:g id="APP">%s</xliff:g>।"</string>
<string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g> लाई सुरक्षित-मोडमा असक्षम गरिएको छ।"</string>
- <string name="recents_history_button_label" msgid="5153358867807604821">"इतिहास"</string>
- <string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"मेटाउनुहोस्"</string>
+ <string name="recents_stack_action_button_label" msgid="6593727103310426253">"सबै हटाउनुहोस्"</string>
<string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"यस अनुप्रयोगले बहु-विन्डोलाई समर्थन गर्दैन"</string>
<string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"अनुप्रयोगले बहु-विन्डोलाई समर्थन गर्दैन"</string>
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"तेर्सो रूपमा विभाजन गर्नुहोस्"</string>
@@ -480,8 +480,7 @@
<string name="notification_importance_max" msgid="5806278962376556491">"सूचना सूचीको शीर्षमा देखाउने, स्क्रिनमा चियाउने र ध्वनि निकाल्न अनुमति दिने"</string>
<string name="notification_more_settings" msgid="816306283396553571">"थप सेटिङहरू"</string>
<string name="notification_done" msgid="5279426047273930175">"सम्पन्न भयो"</string>
- <!-- no translation found for notification_gear_accessibility (94429150213089611) -->
- <skip />
+ <string name="notification_gear_accessibility" msgid="94429150213089611">"<xliff:g id="APP_NAME">%1$s</xliff:g> का सूचनाका लागि नियन्त्रणहरू"</string>
<string name="color_and_appearance" msgid="1254323855964993144">"रंग र रूप"</string>
<string name="night_mode" msgid="3540405868248625488">"रात्री मोड"</string>
<string name="calibrate_display" msgid="5974642573432039217">"प्रदर्शनको स्तर मिलाउनुहोस्"</string>
@@ -501,10 +500,48 @@
<string name="battery_detail_charging_summary" msgid="1279095653533044008">"चार्ज गर्ने समयमा ब्याट्री सेभर उपलब्ध छैन"</string>
<string name="battery_detail_switch_title" msgid="6285872470260795421">"ब्याट्री सेभर"</string>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"कार्यसम्पादन र पृष्ठभूमि डेटा घटाउँछ"</string>
+ <string name="keyboard_key_button_template" msgid="6230056639734377300">"<xliff:g id="NAME">%1$s</xliff:g> बटन"</string>
+ <string name="keyboard_key_home" msgid="2243500072071305073">"Home"</string>
+ <string name="keyboard_key_back" msgid="2337450286042721351">"पछाडि"</string>
+ <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"माथि"</string>
+ <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"तल"</string>
+ <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"बायाँ"</string>
+ <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"दायाँ"</string>
+ <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"केन्द्र"</string>
+ <string name="keyboard_key_tab" msgid="3871485650463164476">"Tab"</string>
+ <string name="keyboard_key_space" msgid="2499861316311153293">"स्पेस"</string>
+ <string name="keyboard_key_enter" msgid="5739632123216118137">"Enter"</string>
+ <string name="keyboard_key_backspace" msgid="1559580097512385854">"ब्याकस्पेस"</string>
+ <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"प्ले गर्नुहोस्/पज गर्नुहोस्"</string>
+ <string name="keyboard_key_media_stop" msgid="2859963958595908962">"रोक्नुहोस्"</string>
+ <string name="keyboard_key_media_next" msgid="1894394911630345607">"अर्को"</string>
+ <string name="keyboard_key_media_previous" msgid="4256072387192967261">"अघिल्लो"</string>
+ <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"रिवाइन्ड गर्नुहोस्"</string>
+ <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"फास्ट फर्वार्ड"</string>
+ <string name="keyboard_key_page_up" msgid="5654098530106845603">"Page Up"</string>
+ <string name="keyboard_key_page_down" msgid="8720502083731906136">"Page Down"</string>
+ <string name="keyboard_key_forward_del" msgid="1391451334716490176">"Delete"</string>
+ <string name="keyboard_key_move_home" msgid="2765693292069487486">"Home"</string>
+ <string name="keyboard_key_move_end" msgid="5901174332047975247">"End"</string>
+ <string name="keyboard_key_insert" msgid="8530501581636082614">"Insert"</string>
+ <string name="keyboard_key_num_lock" msgid="5052537581246772117">"Num Lock"</string>
+ <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"नमप्याड <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"प्रणाली"</string>
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"गृह"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"हालैका"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"पछाडि"</string>
+ <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"सूचनाहरू"</string>
+ <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"किबोर्ड सर्टकटहरू"</string>
+ <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"इनपुट विधिलाई स्विच गर्नुहोस्"</string>
+ <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"अनुप्रयोगहरू"</string>
+ <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"सहायता"</string>
+ <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"ब्राउजर"</string>
+ <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"सम्पर्कहरू"</string>
+ <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"इमेल"</string>
+ <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"IM"</string>
+ <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"संगीत"</string>
+ <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+ <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"पात्रो"</string>
<string name="tuner_full_zen_title" msgid="4540823317772234308">"भोल्युम नियन्त्रणसहित देखाउनुहोस्"</string>
<string name="volume_and_do_not_disturb" msgid="3373784330208603030">"बाधा नपुर्याउनुहोस्"</string>
<string name="volume_dnd_silent" msgid="4363882330723050727">"भोल्युम बटनका सर्टकट"</string>
@@ -540,8 +577,7 @@
<string name="select_keycode" msgid="7413765103381924584">"किबोर्ड बटन चयन गर्नुहोस्"</string>
<string name="preview" msgid="9077832302472282938">"पूर्वावलोकन"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"टाइलहरू थप्न तान्नुहोस्"</string>
- <!-- no translation found for drag_to_remove_tiles (3361212377437088062) -->
- <skip />
+ <string name="drag_to_remove_tiles" msgid="3361212377437088062">"हटाउनका लागि यहाँ तान्नुहोस्"</string>
<string name="qs_edit" msgid="2232596095725105230">"सम्पादन गर्नुहोस्"</string>
<string name="tuner_time" msgid="6572217313285536011">"समय"</string>
<string-array name="clock_options">
@@ -560,4 +596,14 @@
<string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"माथि सार्नुहोस्"</string>
<string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"बाँया सार्नुहोस्"</string>
<string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"दायाँ सार्नुहोस्"</string>
+ <string name="forced_resizable_info_text" msgid="7591061837558867999">"अनुप्रयोग बहु-विन्डोमा काम नगर्न सक्छ"</string>
+ <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"स्थिति <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>। सम्पादन गर्नका लागि डबल ट्याप गर्नुहोस्।"</string>
+ <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>। थप्नका लागि डबल ट्याप गर्नुहोस्।"</string>
+ <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"स्थिति <xliff:g id="POSITION">%1$d</xliff:g>। चयन गर्नका लागि डबल ट्याप गर्नुहोस्।"</string>
+ <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"<xliff:g id="TILE_NAME">%1$s</xliff:g> लाई सार्नुहोस्"</string>
+ <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"<xliff:g id="TILE_NAME">%1$s</xliff:g> लाई हटाउनुहोस्"</string>
+ <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="TILE_NAME">%1$s</xliff:g> लाई स्थिति <xliff:g id="POSITION">%2$d</xliff:g> मा थपियो"</string>
+ <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"<xliff:g id="TILE_NAME">%1$s</xliff:g> लाई हटाइयो"</string>
+ <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="TILE_NAME">%1$s</xliff:g> लाई स्थिति <xliff:g id="POSITION">%2$d</xliff:g> मा सारियो"</string>
+ <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"द्रुत सेटिङ सम्पादक।"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ne-rNP/strings_tv.xml b/packages/SystemUI/res/values-ne-rNP/strings_tv.xml
index 7234d3b..d9245d2 100644
--- a/packages/SystemUI/res/values-ne-rNP/strings_tv.xml
+++ b/packages/SystemUI/res/values-ne-rNP/strings_tv.xml
@@ -26,6 +26,5 @@
<string name="pip_hold_home" msgid="340086535668778109">"PIP लाई नियन्त्रण गर्न "<b>"गृह"</b>" कुञ्जीलाई थिचिरहनुहोस्"</string>
<string name="pip_onboarding_description" msgid="2882896641362814195">"IP लाई नियन्त्रण गर्न गृह बटनलाई थिची होल्ड गर्नुहोस्"</string>
<string name="pip_onboarding_button" msgid="3957426748484904611">"बुझेँ"</string>
- <!-- no translation found for recents_tv_dismiss (3555093879593377731) -->
- <skip />
+ <string name="recents_tv_dismiss" msgid="3555093879593377731">"खारेज गर्नुहोस्"</string>
</resources>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index b49cf66..41075e3 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -168,6 +168,8 @@
<string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"<xliff:g id="APP">%s</xliff:g> sluiten."</string>
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> verwijderd."</string>
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Alle recente apps gesloten."</string>
+ <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+ <skip />
<string name="accessibility_recents_item_launched" msgid="7616039892382525203">"<xliff:g id="APP">%s</xliff:g> starten."</string>
<string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
<string name="accessibility_notification_dismissed" msgid="854211387186306927">"Melding verwijderd."</string>
@@ -309,8 +311,7 @@
<string name="recents_search_bar_label" msgid="8074997400187836677">"zoeken"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"Kan <xliff:g id="APP">%s</xliff:g> niet starten."</string>
<string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g> is uitgeschakeld in de veilige modus"</string>
- <string name="recents_history_button_label" msgid="5153358867807604821">"Geschiedenis"</string>
- <string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Wissen"</string>
+ <string name="recents_stack_action_button_label" msgid="6593727103310426253">"Alles wissen"</string>
<string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"Deze app ondersteunt de modus voor meerdere vensters niet"</string>
<string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"App ondersteunt meerdere vensters niet"</string>
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Horizontaal splitsen"</string>
@@ -499,10 +500,48 @@
<string name="battery_detail_charging_summary" msgid="1279095653533044008">"Accubesparing niet beschikbaar tijdens opladen"</string>
<string name="battery_detail_switch_title" msgid="6285872470260795421">"Accubesparing"</string>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"Vermindert de prestaties en achtergrondgegevens"</string>
+ <string name="keyboard_key_button_template" msgid="6230056639734377300">"Knop <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="keyboard_key_home" msgid="2243500072071305073">"Home"</string>
+ <string name="keyboard_key_back" msgid="2337450286042721351">"Terug"</string>
+ <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"Omhoog"</string>
+ <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"Omlaag"</string>
+ <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"Links"</string>
+ <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"Rechts"</string>
+ <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"Midden"</string>
+ <string name="keyboard_key_tab" msgid="3871485650463164476">"Tab"</string>
+ <string name="keyboard_key_space" msgid="2499861316311153293">"Spatiebalk"</string>
+ <string name="keyboard_key_enter" msgid="5739632123216118137">"Enter"</string>
+ <string name="keyboard_key_backspace" msgid="1559580097512385854">"Backspace"</string>
+ <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"Afspelen/Onderbreken"</string>
+ <string name="keyboard_key_media_stop" msgid="2859963958595908962">"Stoppen"</string>
+ <string name="keyboard_key_media_next" msgid="1894394911630345607">"Volgende"</string>
+ <string name="keyboard_key_media_previous" msgid="4256072387192967261">"Vorige"</string>
+ <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"Terugspoelen"</string>
+ <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"Vooruitspoelen"</string>
+ <string name="keyboard_key_page_up" msgid="5654098530106845603">"Page Up"</string>
+ <string name="keyboard_key_page_down" msgid="8720502083731906136">"Page Down"</string>
+ <string name="keyboard_key_forward_del" msgid="1391451334716490176">"Delete"</string>
+ <string name="keyboard_key_move_home" msgid="2765693292069487486">"Home"</string>
+ <string name="keyboard_key_move_end" msgid="5901174332047975247">"End"</string>
+ <string name="keyboard_key_insert" msgid="8530501581636082614">"Insert"</string>
+ <string name="keyboard_key_num_lock" msgid="5052537581246772117">"Num Lock"</string>
+ <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"<xliff:g id="NAME">%1$s</xliff:g> op numeriek toetsenblok"</string>
<string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"Systeem"</string>
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Startpagina"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Recent"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Terug"</string>
+ <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Meldingen"</string>
+ <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"Sneltoetsen"</string>
+ <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"Invoermethode schakelen"</string>
+ <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"Apps"</string>
+ <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"Assistentie"</string>
+ <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"Browser"</string>
+ <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"Contacten"</string>
+ <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"E-mail"</string>
+ <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"Chat"</string>
+ <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"Muziek"</string>
+ <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+ <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"Agenda"</string>
<string name="tuner_full_zen_title" msgid="4540823317772234308">"Weergeven met volumeknoppen"</string>
<string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Niet storen"</string>
<string name="volume_dnd_silent" msgid="4363882330723050727">"Volumeknoppen als sneltoets"</string>
@@ -557,4 +596,14 @@
<string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Omhoog"</string>
<string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Naar links"</string>
<string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Naar rechts"</string>
+ <string name="forced_resizable_info_text" msgid="7591061837558867999">"De app werkt mogelijk niet met meerdere vensters"</string>
+ <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"Positie <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>. Dubbeltik om te bewerken."</string>
+ <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. Dubbeltik om toe te voegen."</string>
+ <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"Positie <xliff:g id="POSITION">%1$d</xliff:g>. Dubbeltik om te selecteren."</string>
+ <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"<xliff:g id="TILE_NAME">%1$s</xliff:g> verplaatsen"</string>
+ <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"<xliff:g id="TILE_NAME">%1$s</xliff:g> verwijderen"</string>
+ <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="TILE_NAME">%1$s</xliff:g> is toegevoegd op positie <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+ <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"<xliff:g id="TILE_NAME">%1$s</xliff:g> is verwijderd"</string>
+ <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="TILE_NAME">%1$s</xliff:g> is verplaatst naar positie <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+ <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Editor voor \'Snelle instellingen\'."</string>
</resources>
diff --git a/packages/SystemUI/res/values-pa-rIN/strings.xml b/packages/SystemUI/res/values-pa-rIN/strings.xml
index f67c51a..1703a2f 100644
--- a/packages/SystemUI/res/values-pa-rIN/strings.xml
+++ b/packages/SystemUI/res/values-pa-rIN/strings.xml
@@ -168,6 +168,8 @@
<string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"<xliff:g id="APP">%s</xliff:g> ਨੂੰ ਰੱਦ ਕਰੋ।"</string>
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> ਰੱਦ ਕੀਤਾ।"</string>
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"ਸਾਰੀਆਂ ਹਾਲੀਆ ਐਪਲੀਕੇਸ਼ਨਾਂ ਰੱਦ ਕੀਤੀਆਂ।"</string>
+ <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+ <skip />
<string name="accessibility_recents_item_launched" msgid="7616039892382525203">"<xliff:g id="APP">%s</xliff:g> ਚਾਲੂ ਕਰ ਰਿਹਾ ਹੈ।"</string>
<string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
<string name="accessibility_notification_dismissed" msgid="854211387186306927">"ਸੂਚਨਾ ਰੱਦ ਕੀਤੀ।"</string>
@@ -236,8 +238,7 @@
<string name="gps_notification_found_text" msgid="4619274244146446464">"GPS ਵੱਲੋਂ ਸੈਟ ਕੀਤਾ ਨਿਰਧਾਰਿਤ ਸਥਾਨ"</string>
<string name="accessibility_location_active" msgid="2427290146138169014">"ਨਿਰਧਾਰਿਤ ਸਥਾਨ ਸੇਵਾ ਬੇਨਤੀਆਂ ਸਕਿਰਿਆ"</string>
<string name="accessibility_clear_all" msgid="5235938559247164925">"ਸਾਰੀਆਂ ਸੂਚਨਾਵਾਂ ਹਟਾਓ।"</string>
- <!-- no translation found for notification_group_overflow_indicator (1863231301642314183) -->
- <skip />
+ <string name="notification_group_overflow_indicator" msgid="1863231301642314183">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string>
<string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"ਸੂਚਨਾ ਸੈਟਿੰਗਾਂ"</string>
<string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"<xliff:g id="APP_NAME">%s</xliff:g> ਸੈਟਿੰਗਾਂ"</string>
<string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"ਸਕ੍ਰੀਨ ਆਟੋਮੈਟਿਕਲੀ ਰੋਟੇਟ ਕਰੇਗੀ।"</string>
@@ -310,8 +311,7 @@
<string name="recents_search_bar_label" msgid="8074997400187836677">"ਖੋਜੋ"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g> ਨੂੰ ਚਾਲੂ ਨਹੀਂ ਕਰ ਸਕਿਆ।"</string>
<string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g> ਨੂੰ ਸੁਰੱਖਿਅਤ-ਮੋਡ ਵਿੱਚ ਅਯੋਗ ਬਣਾਇਆ ਗਿਆ ਹੈ।"</string>
- <string name="recents_history_button_label" msgid="5153358867807604821">"ਇਤਿਹਾਸ"</string>
- <string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"ਸਾਫ਼ ਕਰੋ"</string>
+ <string name="recents_stack_action_button_label" msgid="6593727103310426253">"ਸਭ ਸਾਫ਼ ਕਰੋ"</string>
<string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"ਇਹ ਐਪ ਮਲਟੀ-ਵਿੰਡੋ ਨੂੰ ਸਮਰਥਨ ਨਹੀਂ ਕਰਦੀ"</string>
<string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"ਐਪ ਮਲਟੀ-ਵਿੰਡੋ ਨੂੰ ਸਮਰਥਨ ਨਹੀਂ ਕਰਦੀ"</string>
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"ਹੌਰੀਜ਼ੌਂਟਲ ਸਪਲਿਟ"</string>
@@ -480,8 +480,7 @@
<string name="notification_importance_max" msgid="5806278962376556491">"ਸੂਚਨਾਵਾਂ ਸੂਚੀ ਦੇ ਸਿਖਰ \'ਤੇ ਵਿਖਾਓ, ਸਕ੍ਰੀਨ \'ਤੇ ਝਲਕ ਵਿਖਾਉਣ ਅਤੇ ਧੁਨੀ ਦੀ ਮਨਜ਼ੂਰੀ ਦਿਓ"</string>
<string name="notification_more_settings" msgid="816306283396553571">"ਹੋਰ ਸੈਟਿੰਗਾਂ"</string>
<string name="notification_done" msgid="5279426047273930175">"ਹੋ ਗਿਆ"</string>
- <!-- no translation found for notification_gear_accessibility (94429150213089611) -->
- <skip />
+ <string name="notification_gear_accessibility" msgid="94429150213089611">"<xliff:g id="APP_NAME">%1$s</xliff:g> ਸੂਚਨਾ ਕੰਟਰੋਲ"</string>
<string name="color_and_appearance" msgid="1254323855964993144">"ਰੰਗ ਅਤੇ ਵਿਖਾਲਾ"</string>
<string name="night_mode" msgid="3540405868248625488">"ਰਾਤ ਮੋਡ"</string>
<string name="calibrate_display" msgid="5974642573432039217">"ਡਿਸਪਲੇ ਨੂੰ ਕੈਲੀਬ੍ਰੇਟ ਕਰੋ"</string>
@@ -501,10 +500,48 @@
<string name="battery_detail_charging_summary" msgid="1279095653533044008">"ਬੈਟਰੀ ਸੇਵਰ ਚਾਰਜਿੰਗ ਦੌਰਾਨ ਉਪਲਬਧ ਨਹੀਂ ਹੈ"</string>
<string name="battery_detail_switch_title" msgid="6285872470260795421">"ਬੈਟਰੀ ਸੇਵਰ"</string>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"ਕਾਰਗੁਜ਼ਾਰੀ ਅਤੇ ਬੈਕਗ੍ਰਾਊਂਡ ਡੈਟੇ ਨੂੰ ਘਟਾਉਂਦਾ ਹੈ"</string>
+ <string name="keyboard_key_button_template" msgid="6230056639734377300">"ਬਟਨ <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="keyboard_key_home" msgid="2243500072071305073">"Home"</string>
+ <string name="keyboard_key_back" msgid="2337450286042721351">"Back"</string>
+ <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"Up"</string>
+ <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"Down"</string>
+ <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"Left"</string>
+ <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"Right"</string>
+ <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"Center"</string>
+ <string name="keyboard_key_tab" msgid="3871485650463164476">"Tab"</string>
+ <string name="keyboard_key_space" msgid="2499861316311153293">"Space"</string>
+ <string name="keyboard_key_enter" msgid="5739632123216118137">"Enter"</string>
+ <string name="keyboard_key_backspace" msgid="1559580097512385854">"Backspace"</string>
+ <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"Play/Pause"</string>
+ <string name="keyboard_key_media_stop" msgid="2859963958595908962">"Stop"</string>
+ <string name="keyboard_key_media_next" msgid="1894394911630345607">"Next"</string>
+ <string name="keyboard_key_media_previous" msgid="4256072387192967261">"Previous"</string>
+ <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"Rewind"</string>
+ <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"Fast Forward"</string>
+ <string name="keyboard_key_page_up" msgid="5654098530106845603">"Page Up"</string>
+ <string name="keyboard_key_page_down" msgid="8720502083731906136">"Page Down"</string>
+ <string name="keyboard_key_forward_del" msgid="1391451334716490176">"Delete"</string>
+ <string name="keyboard_key_move_home" msgid="2765693292069487486">"Home"</string>
+ <string name="keyboard_key_move_end" msgid="5901174332047975247">"End"</string>
+ <string name="keyboard_key_insert" msgid="8530501581636082614">"Insert"</string>
+ <string name="keyboard_key_num_lock" msgid="5052537581246772117">"Num Lock"</string>
+ <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"Numpad <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"ਸਿਸਟਮ"</string>
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"ਮੁੱਖ ਸਕ੍ਰੀਨ"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"ਹਾਲੀਆ"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"ਪਿੱਛੇ"</string>
+ <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"ਸੂਚਨਾਵਾਂ"</string>
+ <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"ਕੀ-ਬੋਰਡ ਸ਼ਾਰਟਕੱਟ"</string>
+ <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"ਵਾਪਸ ਇਨਪੁੱਟ ਵਿਧੀ \'ਤੇ ਬਦਲੋ"</string>
+ <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"ਐਪਲੀਕੇਸ਼ਨਾਂ"</string>
+ <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"ਸਹਾਇਕ"</string>
+ <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"ਬ੍ਰਾਊਜ਼ਰ"</string>
+ <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"ਸੰਪਰਕ"</string>
+ <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"ਈਮੇਲ"</string>
+ <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"IM"</string>
+ <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"ਸੰਗੀਤ"</string>
+ <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+ <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"ਕੈਲੰਡਰ"</string>
<string name="tuner_full_zen_title" msgid="4540823317772234308">"ਵੌਲਯੂਮ ਕੰਟਰੋਲਾਂ ਨਾਲ ਵਿਖਾਓ"</string>
<string name="volume_and_do_not_disturb" msgid="3373784330208603030">"ਮੈਨੂੰ ਪਰੇਸ਼ਾਨ ਨਾ ਕਰੋ"</string>
<string name="volume_dnd_silent" msgid="4363882330723050727">"ਵੌਲਯੂਮ ਬਟਨ ਸ਼ਾਰਟਕੱਟ"</string>
@@ -540,8 +577,7 @@
<string name="select_keycode" msgid="7413765103381924584">"ਕੀ-ਬੋਰਡ ਬਟਨ ਚੁਣੋ"</string>
<string name="preview" msgid="9077832302472282938">"ਝਲਕ"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"ਟਾਇਲਾਂ ਨੂੰ ਸ਼ਾਮਲ ਕਰਨ ਲਈ ਘਸੀਟੋ"</string>
- <!-- no translation found for drag_to_remove_tiles (3361212377437088062) -->
- <skip />
+ <string name="drag_to_remove_tiles" msgid="3361212377437088062">"ਹਟਾਉਣ ਲਈ ਇੱਥੇ ਘਸੀਟੋ"</string>
<string name="qs_edit" msgid="2232596095725105230">"ਸੰਪਾਦਨ ਕਰੋ"</string>
<string name="tuner_time" msgid="6572217313285536011">"ਸਮਾਂ"</string>
<string-array name="clock_options">
@@ -560,4 +596,14 @@
<string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"ਉੱਪਰ ਲੈ ਜਾਓ"</string>
<string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"ਖੱਬੇ ਲੈ ਜਾਓ"</string>
<string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"ਸੱਜੇ ਲੈ ਜਾਓ"</string>
+ <string name="forced_resizable_info_text" msgid="7591061837558867999">"ਹੋ ਸਕਦਾ ਹੈ ਕਿ ਐਪ ਮਲਟੀ-ਵਿੰਡੋ ਨਾਲ ਕੰਮ ਨਾ ਕਰੇ"</string>
+ <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"ਸਥਿਤੀ <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>। ਸੰਪਾਦਨ ਲਈ ਦੋ ਵਾਰ ਟੈਪ ਕਰੋ।"</string>
+ <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>। ਸ਼ਾਮਲ ਕਰਨ ਲਈ ਦੋ ਵਾਰ ਟੈਪ ਕਰੋ।"</string>
+ <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"ਸਥਿਤੀ <xliff:g id="POSITION">%1$d</xliff:g>। ਚੁਣਨ ਲਈ ਦੋ ਵਾਰ ਟੈਪ ਕਰੋ।"</string>
+ <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"<xliff:g id="TILE_NAME">%1$s</xliff:g> ਨੂੰ ਤਬਦੀਲ ਕਰੋ"</string>
+ <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"<xliff:g id="TILE_NAME">%1$s</xliff:g> ਹਟਾਓ"</string>
+ <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="TILE_NAME">%1$s</xliff:g> ਨੂੰ <xliff:g id="POSITION">%2$d</xliff:g> ਸਥਿਤੀ \'ਤੇ ਸ਼ਾਮਲ ਕੀਤਾ ਗਿਆ"</string>
+ <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"<xliff:g id="TILE_NAME">%1$s</xliff:g> ਨੂੰ ਹਟਾਇਆ ਗਿਆ"</string>
+ <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="TILE_NAME">%1$s</xliff:g> ਨੂੰ <xliff:g id="POSITION">%2$d</xliff:g> ਸਥਿਤੀ \'ਤੇ ਤਬਦੀਲ ਕੀਤਾ ਗਿਆ"</string>
+ <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"ਤਤਕਾਲ ਸੈਟਿੰਗਾਂ ਸੰਪਾਦਕ।"</string>
</resources>
diff --git a/packages/SystemUI/res/values-pa-rIN/strings_tv.xml b/packages/SystemUI/res/values-pa-rIN/strings_tv.xml
index 78a5322..7cbda258 100644
--- a/packages/SystemUI/res/values-pa-rIN/strings_tv.xml
+++ b/packages/SystemUI/res/values-pa-rIN/strings_tv.xml
@@ -26,6 +26,5 @@
<string name="pip_hold_home" msgid="340086535668778109">"PIP ਕੰਟਰੋਲ ਕਰਨ ਲਈ "<b>"ਹੋਮ"</b>" ਦਬਾਈ ਰੱਖੋ"</string>
<string name="pip_onboarding_description" msgid="2882896641362814195">"PIP ਨੂੰ ਕੰਟਰੋਲ ਕਰਨ ਲਈ ਹੋਮ ਬਟਨ ਨੂੰ ਦੱਬੋ ਅਤੇ ਦਬਾਈ ਰੱਖੋ"</string>
<string name="pip_onboarding_button" msgid="3957426748484904611">"ਸਮਝ ਲਿਆ"</string>
- <!-- no translation found for recents_tv_dismiss (3555093879593377731) -->
- <skip />
+ <string name="recents_tv_dismiss" msgid="3555093879593377731">"ਖ਼ਾਰਜ ਕਰੋ"</string>
</resources>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index 12452f6..297b849 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -170,6 +170,8 @@
<string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Usuń stąd <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g>: zamknięto."</string>
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Wszystkie ostatnie aplikacje zostały zamknięte."</string>
+ <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+ <skip />
<string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Uruchamiam <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
<string name="accessibility_notification_dismissed" msgid="854211387186306927">"Zamknięto powiadomienie."</string>
@@ -238,8 +240,7 @@
<string name="gps_notification_found_text" msgid="4619274244146446464">"Lokalizacja z GPSa"</string>
<string name="accessibility_location_active" msgid="2427290146138169014">"Prośby o lokalizację są aktywne"</string>
<string name="accessibility_clear_all" msgid="5235938559247164925">"Usuń wszystkie powiadomienia."</string>
- <!-- no translation found for notification_group_overflow_indicator (1863231301642314183) -->
- <skip />
+ <string name="notification_group_overflow_indicator" msgid="1863231301642314183">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string>
<string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"Ustawienia powiadomień"</string>
<string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"Ustawienia aplikacji <xliff:g id="APP_NAME">%s</xliff:g>"</string>
<string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Ekran zostanie obrócony automatycznie."</string>
@@ -312,8 +313,7 @@
<string name="recents_search_bar_label" msgid="8074997400187836677">"szukaj"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"Nie udało się uruchomić aplikacji <xliff:g id="APP">%s</xliff:g>."</string>
<string name="recents_launch_disabled_message" msgid="1624523193008871793">"Aplikacja <xliff:g id="APP">%s</xliff:g> została wyłączona w trybie bezpiecznym."</string>
- <string name="recents_history_button_label" msgid="5153358867807604821">"Historia"</string>
- <string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Wyczyść"</string>
+ <string name="recents_stack_action_button_label" msgid="6593727103310426253">"Wyczyść wszystko"</string>
<string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"Ta aplikacja nie obsługuje trybu wielu okien"</string>
<string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"Aplikacja nie obsługuje trybu wielu okien"</string>
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Podziel poziomo"</string>
@@ -482,8 +482,7 @@
<string name="notification_importance_max" msgid="5806278962376556491">"Pokazuj na początku listy powiadomień, wyświetlaj na ekranie i sygnalizuj dźwiękiem"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Więcej ustawień"</string>
<string name="notification_done" msgid="5279426047273930175">"Gotowe"</string>
- <!-- no translation found for notification_gear_accessibility (94429150213089611) -->
- <skip />
+ <string name="notification_gear_accessibility" msgid="94429150213089611">"<xliff:g id="APP_NAME">%1$s</xliff:g> – ustawienia powiadomień"</string>
<string name="color_and_appearance" msgid="1254323855964993144">"Kolor i wygląd"</string>
<string name="night_mode" msgid="3540405868248625488">"Tryb nocny"</string>
<string name="calibrate_display" msgid="5974642573432039217">"Kalibracja wyświetlacza"</string>
@@ -503,10 +502,48 @@
<string name="battery_detail_charging_summary" msgid="1279095653533044008">"Oszczędzanie baterii nie jest dostępne podczas ładowania"</string>
<string name="battery_detail_switch_title" msgid="6285872470260795421">"Oszczędzanie baterii"</string>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"Zmniejsza wydajność i ogranicza dane w tle"</string>
+ <string name="keyboard_key_button_template" msgid="6230056639734377300">"Przycisk <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="keyboard_key_home" msgid="2243500072071305073">"Home"</string>
+ <string name="keyboard_key_back" msgid="2337450286042721351">"Wstecz"</string>
+ <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"W górę"</string>
+ <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"W dół"</string>
+ <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"W lewo"</string>
+ <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"W prawo"</string>
+ <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"Do środka"</string>
+ <string name="keyboard_key_tab" msgid="3871485650463164476">"Tab"</string>
+ <string name="keyboard_key_space" msgid="2499861316311153293">"Spacja"</string>
+ <string name="keyboard_key_enter" msgid="5739632123216118137">"Enter"</string>
+ <string name="keyboard_key_backspace" msgid="1559580097512385854">"Backspace"</string>
+ <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"Odtwórz/wstrzymaj"</string>
+ <string name="keyboard_key_media_stop" msgid="2859963958595908962">"Zatrzymaj"</string>
+ <string name="keyboard_key_media_next" msgid="1894394911630345607">"Następny"</string>
+ <string name="keyboard_key_media_previous" msgid="4256072387192967261">"Poprzedni"</string>
+ <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"Przewiń do tyłu"</string>
+ <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"Przewiń do przodu"</string>
+ <string name="keyboard_key_page_up" msgid="5654098530106845603">"Page Up"</string>
+ <string name="keyboard_key_page_down" msgid="8720502083731906136">"Page Down"</string>
+ <string name="keyboard_key_forward_del" msgid="1391451334716490176">"Delete"</string>
+ <string name="keyboard_key_move_home" msgid="2765693292069487486">"Home"</string>
+ <string name="keyboard_key_move_end" msgid="5901174332047975247">"End"</string>
+ <string name="keyboard_key_insert" msgid="8530501581636082614">"Insert"</string>
+ <string name="keyboard_key_num_lock" msgid="5052537581246772117">"Num Lock"</string>
+ <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"Klawiatura numeryczna <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"System"</string>
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Ekran główny"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Ostatnie"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Wstecz"</string>
+ <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Powiadomienia"</string>
+ <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"Skróty klawiszowe"</string>
+ <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"Przełącz metodę wprowadzania"</string>
+ <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"Aplikacje"</string>
+ <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"Pomoc"</string>
+ <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"Przeglądarka"</string>
+ <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"Kontakty"</string>
+ <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"E-mail"</string>
+ <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"Komunikator"</string>
+ <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"Muzyka"</string>
+ <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+ <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"Kalendarz"</string>
<string name="tuner_full_zen_title" msgid="4540823317772234308">"Pokazuj z regulacją głośności"</string>
<string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Nie przeszkadzać"</string>
<string name="volume_dnd_silent" msgid="4363882330723050727">"Wł./wył. przyciskami głośności"</string>
@@ -561,4 +598,14 @@
<string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Przesuń w górę"</string>
<string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Przesuń w lewo"</string>
<string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Przesuń w prawo"</string>
+ <string name="forced_resizable_info_text" msgid="7591061837558867999">"Aplikacja może nie działać w trybie wielu okien"</string>
+ <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"Położenie <xliff:g id="POSITION">%1$d</xliff:g>, kafelek <xliff:g id="TILE_NAME">%2$s</xliff:g>. Kliknij dwukrotnie, by edytować."</string>
+ <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"Kafelek <xliff:g id="TILE_NAME">%1$s</xliff:g>. Kliknij dwukrotnie, by dodać."</string>
+ <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"Położenie <xliff:g id="POSITION">%1$d</xliff:g>. Kliknij dwukrotnie, by wybrać."</string>
+ <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"Przenieś kafelek <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"Usuń kafelek <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"Kafelek <xliff:g id="TILE_NAME">%1$s</xliff:g> został dodany w położeniu <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+ <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"Kafelek <xliff:g id="TILE_NAME">%1$s</xliff:g> został usunięty"</string>
+ <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"Kafelek <xliff:g id="TILE_NAME">%1$s</xliff:g> przeniesiony w położenie <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+ <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Edytor szybkich ustawień."</string>
</resources>
diff --git a/packages/SystemUI/res/values-pl/strings_tv.xml b/packages/SystemUI/res/values-pl/strings_tv.xml
index 78bb18e..70be3d9 100644
--- a/packages/SystemUI/res/values-pl/strings_tv.xml
+++ b/packages/SystemUI/res/values-pl/strings_tv.xml
@@ -26,6 +26,5 @@
<string name="pip_hold_home" msgid="340086535668778109">"Przytrzymaj "<b>"EKRAN GŁÓWNY"</b>", by sterować PIP"</string>
<string name="pip_onboarding_description" msgid="2882896641362814195">"Przytrzymaj przycisk EKRAN GŁÓWNY, by sterować PIP"</string>
<string name="pip_onboarding_button" msgid="3957426748484904611">"OK"</string>
- <!-- no translation found for recents_tv_dismiss (3555093879593377731) -->
- <skip />
+ <string name="recents_tv_dismiss" msgid="3555093879593377731">"Zamknij"</string>
</resources>
diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml
index 10d3181..eb08d99 100644
--- a/packages/SystemUI/res/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res/values-pt-rBR/strings.xml
@@ -168,6 +168,8 @@
<string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Descartar <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> descartado."</string>
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Todos os apps recentes foram dispensados."</string>
+ <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+ <skip />
<string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Iniciando <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
<string name="accessibility_notification_dismissed" msgid="854211387186306927">"Notificação dispensada."</string>
@@ -236,8 +238,7 @@
<string name="gps_notification_found_text" msgid="4619274244146446464">"Local definido por GPS"</string>
<string name="accessibility_location_active" msgid="2427290146138169014">"Solicitações de localização ativas"</string>
<string name="accessibility_clear_all" msgid="5235938559247164925">"Limpar todas as notificações."</string>
- <!-- no translation found for notification_group_overflow_indicator (1863231301642314183) -->
- <skip />
+ <string name="notification_group_overflow_indicator" msgid="1863231301642314183">"Mais <xliff:g id="NUMBER">%s</xliff:g>"</string>
<string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"Configurações de notificação"</string>
<string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"Configurações de <xliff:g id="APP_NAME">%s</xliff:g>"</string>
<string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"A tela girará automaticamente."</string>
@@ -310,8 +311,7 @@
<string name="recents_search_bar_label" msgid="8074997400187836677">"pesquisar"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"Não foi possível iniciar <xliff:g id="APP">%s</xliff:g>."</string>
<string name="recents_launch_disabled_message" msgid="1624523193008871793">"O app <xliff:g id="APP">%s</xliff:g> está desativado no modo de segurança."</string>
- <string name="recents_history_button_label" msgid="5153358867807604821">"Histórico"</string>
- <string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Limpar"</string>
+ <string name="recents_stack_action_button_label" msgid="6593727103310426253">"Limpar tudo"</string>
<string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"Este app não é compatível com o modo de várias janelas"</string>
<string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"O app não é compatível com o modo de várias janelas"</string>
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Divisão horizontal"</string>
@@ -480,8 +480,7 @@
<string name="notification_importance_max" msgid="5806278962376556491">"Mostrar na parte superior da lista de notificações, mostrar parcialmente na tela e permitir sons"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Mais configurações"</string>
<string name="notification_done" msgid="5279426047273930175">"Concluído"</string>
- <!-- no translation found for notification_gear_accessibility (94429150213089611) -->
- <skip />
+ <string name="notification_gear_accessibility" msgid="94429150213089611">"Controles de notificação do <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="color_and_appearance" msgid="1254323855964993144">"Cor e aparência"</string>
<string name="night_mode" msgid="3540405868248625488">"Modo noturno"</string>
<string name="calibrate_display" msgid="5974642573432039217">"Calibrar tela"</string>
@@ -501,10 +500,48 @@
<string name="battery_detail_charging_summary" msgid="1279095653533044008">"A Economia de bateria não fica disponível durante o carregamento"</string>
<string name="battery_detail_switch_title" msgid="6285872470260795421">"Economia de bateria"</string>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"Reduz o desempenho e os dados em segundo plano"</string>
+ <string name="keyboard_key_button_template" msgid="6230056639734377300">"Botão <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="keyboard_key_home" msgid="2243500072071305073">"Home"</string>
+ <string name="keyboard_key_back" msgid="2337450286042721351">"Voltar"</string>
+ <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"Para cima"</string>
+ <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"Para baixo"</string>
+ <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"Para a esquerda"</string>
+ <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"Para a direita"</string>
+ <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"Centralizar"</string>
+ <string name="keyboard_key_tab" msgid="3871485650463164476">"Tab"</string>
+ <string name="keyboard_key_space" msgid="2499861316311153293">"Space"</string>
+ <string name="keyboard_key_enter" msgid="5739632123216118137">"Enter"</string>
+ <string name="keyboard_key_backspace" msgid="1559580097512385854">"Barra de espaço"</string>
+ <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"Reproduzir/pausar"</string>
+ <string name="keyboard_key_media_stop" msgid="2859963958595908962">"Parar"</string>
+ <string name="keyboard_key_media_next" msgid="1894394911630345607">"Avançar"</string>
+ <string name="keyboard_key_media_previous" msgid="4256072387192967261">"Anterior"</string>
+ <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"Retroceder"</string>
+ <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"Avançar rapidamente"</string>
+ <string name="keyboard_key_page_up" msgid="5654098530106845603">"Page Up"</string>
+ <string name="keyboard_key_page_down" msgid="8720502083731906136">"Page Down"</string>
+ <string name="keyboard_key_forward_del" msgid="1391451334716490176">"Delete"</string>
+ <string name="keyboard_key_move_home" msgid="2765693292069487486">"Home"</string>
+ <string name="keyboard_key_move_end" msgid="5901174332047975247">"End"</string>
+ <string name="keyboard_key_insert" msgid="8530501581636082614">"Insert"</string>
+ <string name="keyboard_key_num_lock" msgid="5052537581246772117">"Num Lock"</string>
+ <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"Numpad <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"Sistema"</string>
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Início"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Recentes"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Voltar"</string>
+ <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Notificações"</string>
+ <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"Atalhos do teclado"</string>
+ <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"Alterar o método de entrada"</string>
+ <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"Aplicativos"</string>
+ <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"Assistente"</string>
+ <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"Navegador"</string>
+ <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"Contatos"</string>
+ <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"E-mail"</string>
+ <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"Mensagens instantâneas"</string>
+ <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"Música"</string>
+ <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+ <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"Agenda"</string>
<string name="tuner_full_zen_title" msgid="4540823317772234308">"Mostrar com controles de volume"</string>
<string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Não perturbe"</string>
<string name="volume_dnd_silent" msgid="4363882330723050727">"Atalho de botões de volume"</string>
@@ -559,4 +596,14 @@
<string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Mover para cima"</string>
<string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Mover para a esquerda"</string>
<string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Mover para a direita"</string>
+ <string name="forced_resizable_info_text" msgid="7591061837558867999">"É possível que o app não funcione com várias janelas"</string>
+ <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"Posição <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>. Toque duas vezes para editar."</string>
+ <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. Toque duas vezes para adicionar."</string>
+ <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"Posição <xliff:g id="POSITION">%1$d</xliff:g>. Toque duas vezes para selecionar."</string>
+ <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"Move <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"Remove <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="TILE_NAME">%1$s</xliff:g> é adicionado à posição <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+ <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"<xliff:g id="TILE_NAME">%1$s</xliff:g> é removido"</string>
+ <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="TILE_NAME">%1$s</xliff:g> movido para a posição <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+ <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Editor de configurações rápidas."</string>
</resources>
diff --git a/packages/SystemUI/res/values-pt-rBR/strings_tv.xml b/packages/SystemUI/res/values-pt-rBR/strings_tv.xml
index 6061af3..0827f9c7 100644
--- a/packages/SystemUI/res/values-pt-rBR/strings_tv.xml
+++ b/packages/SystemUI/res/values-pt-rBR/strings_tv.xml
@@ -26,6 +26,5 @@
<string name="pip_hold_home" msgid="340086535668778109">"Mantenha "<b>"INÍCIO"</b>" pressionado para controlar o PIP"</string>
<string name="pip_onboarding_description" msgid="2882896641362814195">"Mantenha a tecla \"HOME\" pressionada para controlar o PIP"</string>
<string name="pip_onboarding_button" msgid="3957426748484904611">"Entendi"</string>
- <!-- no translation found for recents_tv_dismiss (3555093879593377731) -->
- <skip />
+ <string name="recents_tv_dismiss" msgid="3555093879593377731">"Dispensar"</string>
</resources>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index 7a2866d..bba2f3e 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -168,6 +168,8 @@
<string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Ignorar <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> ignorado."</string>
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Todas as aplicações recentes foram ignoradas."</string>
+ <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+ <skip />
<string name="accessibility_recents_item_launched" msgid="7616039892382525203">"A iniciar <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
<string name="accessibility_notification_dismissed" msgid="854211387186306927">"Notificação ignorada."</string>
@@ -236,8 +238,7 @@
<string name="gps_notification_found_text" msgid="4619274244146446464">"Localização definida por GPS"</string>
<string name="accessibility_location_active" msgid="2427290146138169014">"Pedidos de localização ativos"</string>
<string name="accessibility_clear_all" msgid="5235938559247164925">"Limpar todas as notificações."</string>
- <!-- no translation found for notification_group_overflow_indicator (1863231301642314183) -->
- <skip />
+ <string name="notification_group_overflow_indicator" msgid="1863231301642314183">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string>
<string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"Definições de notificação"</string>
<string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"Definições do <xliff:g id="APP_NAME">%s</xliff:g>"</string>
<string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"O ecrã será rodado automaticamente."</string>
@@ -310,8 +311,7 @@
<string name="recents_search_bar_label" msgid="8074997400187836677">"pesquisar"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"Não foi possível iniciar o <xliff:g id="APP">%s</xliff:g>."</string>
<string name="recents_launch_disabled_message" msgid="1624523193008871793">"O <xliff:g id="APP">%s</xliff:g> está desativado no modo de segurança."</string>
- <string name="recents_history_button_label" msgid="5153358867807604821">"Histórico"</string>
- <string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Limpar"</string>
+ <string name="recents_stack_action_button_label" msgid="6593727103310426253">"Limpar tudo"</string>
<string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"Esta aplicação não é compatível com várias janelas"</string>
<string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"A aplicação não é compatível com várias janelas"</string>
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Divisão horizontal"</string>
@@ -480,8 +480,7 @@
<string name="notification_importance_max" msgid="5806278962376556491">"Mostrar na parte superior da lista de notificações, mostrar no ecrã e permitir som"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Mais definições"</string>
<string name="notification_done" msgid="5279426047273930175">"Concluído"</string>
- <!-- no translation found for notification_gear_accessibility (94429150213089611) -->
- <skip />
+ <string name="notification_gear_accessibility" msgid="94429150213089611">"Controlos de notificações do <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="color_and_appearance" msgid="1254323855964993144">"Cor e aspeto"</string>
<string name="night_mode" msgid="3540405868248625488">"Modo noturno"</string>
<string name="calibrate_display" msgid="5974642573432039217">"Calibrar ecrã"</string>
@@ -501,10 +500,48 @@
<string name="battery_detail_charging_summary" msgid="1279095653533044008">"Poupança de bateria não disponível durante o carregamento"</string>
<string name="battery_detail_switch_title" msgid="6285872470260795421">"Poupança de bateria"</string>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"Reduz o desempenho e os dados de segundo plano"</string>
+ <string name="keyboard_key_button_template" msgid="6230056639734377300">"Botão <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="keyboard_key_home" msgid="2243500072071305073">"Início"</string>
+ <string name="keyboard_key_back" msgid="2337450286042721351">"Anterior"</string>
+ <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"Para cima"</string>
+ <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"Para baixo"</string>
+ <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"Para a esquerda"</string>
+ <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"Para a direita"</string>
+ <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"Ao centro"</string>
+ <string name="keyboard_key_tab" msgid="3871485650463164476">"Tabulação"</string>
+ <string name="keyboard_key_space" msgid="2499861316311153293">"Espaço"</string>
+ <string name="keyboard_key_enter" msgid="5739632123216118137">"Enter"</string>
+ <string name="keyboard_key_backspace" msgid="1559580097512385854">"Retrocesso"</string>
+ <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"Reproduzir/interromper"</string>
+ <string name="keyboard_key_media_stop" msgid="2859963958595908962">"Parar"</string>
+ <string name="keyboard_key_media_next" msgid="1894394911630345607">"Seguinte"</string>
+ <string name="keyboard_key_media_previous" msgid="4256072387192967261">"Anterior"</string>
+ <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"Recuar"</string>
+ <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"Avançar"</string>
+ <string name="keyboard_key_page_up" msgid="5654098530106845603">"Página para cima"</string>
+ <string name="keyboard_key_page_down" msgid="8720502083731906136">"Página para baixo"</string>
+ <string name="keyboard_key_forward_del" msgid="1391451334716490176">"Eliminar"</string>
+ <string name="keyboard_key_move_home" msgid="2765693292069487486">"Início"</string>
+ <string name="keyboard_key_move_end" msgid="5901174332047975247">"Fim"</string>
+ <string name="keyboard_key_insert" msgid="8530501581636082614">"Inserir"</string>
+ <string name="keyboard_key_num_lock" msgid="5052537581246772117">"Num Lock"</string>
+ <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"Teclado numérico <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"Sistema"</string>
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Página inicial"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Recentes"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Anterior"</string>
+ <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Notificações"</string>
+ <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"Atalhos de teclado"</string>
+ <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"Alternar o método de introdução"</string>
+ <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"Aplicações"</string>
+ <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"Assistência"</string>
+ <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"Navegador"</string>
+ <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"Contactos"</string>
+ <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"Email"</string>
+ <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"IM"</string>
+ <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"Música"</string>
+ <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+ <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"Calendário"</string>
<string name="tuner_full_zen_title" msgid="4540823317772234308">"Mostrar com controlos de volume"</string>
<string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Não incomodar"</string>
<string name="volume_dnd_silent" msgid="4363882330723050727">"Atalho dos botões de volume"</string>
@@ -559,4 +596,14 @@
<string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Mover para cima"</string>
<string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Mover para a esquerda"</string>
<string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Mover para a direita"</string>
+ <string name="forced_resizable_info_text" msgid="7591061837558867999">"A aplicação pode não funcionar com multijanelas"</string>
+ <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"Posição <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>. Toque duas vezes para editar."</string>
+ <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. Toque duas vezes para adicionar."</string>
+ <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"Posição <xliff:g id="POSITION">%1$d</xliff:g>. Toque duas vezes para selecionar."</string>
+ <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"Mover <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"Remover <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="TILE_NAME">%1$s</xliff:g> adicionado à posição <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+ <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"<xliff:g id="TILE_NAME">%1$s</xliff:g> removido"</string>
+ <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="TILE_NAME">%1$s</xliff:g> movido para a posição <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+ <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Editor de definições rápidas."</string>
</resources>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings_tv.xml b/packages/SystemUI/res/values-pt-rPT/strings_tv.xml
index 78d1352..2f465d2 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings_tv.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings_tv.xml
@@ -26,6 +26,5 @@
<string name="pip_hold_home" msgid="340086535668778109">"Prima sem soltar o botão "<b>"HOME"</b>" para controlar o PIP"</string>
<string name="pip_onboarding_description" msgid="2882896641362814195">"Prima sem soltar o botão HOME para controlar o PIP"</string>
<string name="pip_onboarding_button" msgid="3957426748484904611">"Compreendi"</string>
- <!-- no translation found for recents_tv_dismiss (3555093879593377731) -->
- <skip />
+ <string name="recents_tv_dismiss" msgid="3555093879593377731">"Ignorar"</string>
</resources>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index 10d3181..eb08d99 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -168,6 +168,8 @@
<string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Descartar <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> descartado."</string>
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Todos os apps recentes foram dispensados."</string>
+ <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+ <skip />
<string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Iniciando <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
<string name="accessibility_notification_dismissed" msgid="854211387186306927">"Notificação dispensada."</string>
@@ -236,8 +238,7 @@
<string name="gps_notification_found_text" msgid="4619274244146446464">"Local definido por GPS"</string>
<string name="accessibility_location_active" msgid="2427290146138169014">"Solicitações de localização ativas"</string>
<string name="accessibility_clear_all" msgid="5235938559247164925">"Limpar todas as notificações."</string>
- <!-- no translation found for notification_group_overflow_indicator (1863231301642314183) -->
- <skip />
+ <string name="notification_group_overflow_indicator" msgid="1863231301642314183">"Mais <xliff:g id="NUMBER">%s</xliff:g>"</string>
<string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"Configurações de notificação"</string>
<string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"Configurações de <xliff:g id="APP_NAME">%s</xliff:g>"</string>
<string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"A tela girará automaticamente."</string>
@@ -310,8 +311,7 @@
<string name="recents_search_bar_label" msgid="8074997400187836677">"pesquisar"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"Não foi possível iniciar <xliff:g id="APP">%s</xliff:g>."</string>
<string name="recents_launch_disabled_message" msgid="1624523193008871793">"O app <xliff:g id="APP">%s</xliff:g> está desativado no modo de segurança."</string>
- <string name="recents_history_button_label" msgid="5153358867807604821">"Histórico"</string>
- <string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Limpar"</string>
+ <string name="recents_stack_action_button_label" msgid="6593727103310426253">"Limpar tudo"</string>
<string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"Este app não é compatível com o modo de várias janelas"</string>
<string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"O app não é compatível com o modo de várias janelas"</string>
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Divisão horizontal"</string>
@@ -480,8 +480,7 @@
<string name="notification_importance_max" msgid="5806278962376556491">"Mostrar na parte superior da lista de notificações, mostrar parcialmente na tela e permitir sons"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Mais configurações"</string>
<string name="notification_done" msgid="5279426047273930175">"Concluído"</string>
- <!-- no translation found for notification_gear_accessibility (94429150213089611) -->
- <skip />
+ <string name="notification_gear_accessibility" msgid="94429150213089611">"Controles de notificação do <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="color_and_appearance" msgid="1254323855964993144">"Cor e aparência"</string>
<string name="night_mode" msgid="3540405868248625488">"Modo noturno"</string>
<string name="calibrate_display" msgid="5974642573432039217">"Calibrar tela"</string>
@@ -501,10 +500,48 @@
<string name="battery_detail_charging_summary" msgid="1279095653533044008">"A Economia de bateria não fica disponível durante o carregamento"</string>
<string name="battery_detail_switch_title" msgid="6285872470260795421">"Economia de bateria"</string>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"Reduz o desempenho e os dados em segundo plano"</string>
+ <string name="keyboard_key_button_template" msgid="6230056639734377300">"Botão <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="keyboard_key_home" msgid="2243500072071305073">"Home"</string>
+ <string name="keyboard_key_back" msgid="2337450286042721351">"Voltar"</string>
+ <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"Para cima"</string>
+ <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"Para baixo"</string>
+ <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"Para a esquerda"</string>
+ <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"Para a direita"</string>
+ <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"Centralizar"</string>
+ <string name="keyboard_key_tab" msgid="3871485650463164476">"Tab"</string>
+ <string name="keyboard_key_space" msgid="2499861316311153293">"Space"</string>
+ <string name="keyboard_key_enter" msgid="5739632123216118137">"Enter"</string>
+ <string name="keyboard_key_backspace" msgid="1559580097512385854">"Barra de espaço"</string>
+ <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"Reproduzir/pausar"</string>
+ <string name="keyboard_key_media_stop" msgid="2859963958595908962">"Parar"</string>
+ <string name="keyboard_key_media_next" msgid="1894394911630345607">"Avançar"</string>
+ <string name="keyboard_key_media_previous" msgid="4256072387192967261">"Anterior"</string>
+ <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"Retroceder"</string>
+ <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"Avançar rapidamente"</string>
+ <string name="keyboard_key_page_up" msgid="5654098530106845603">"Page Up"</string>
+ <string name="keyboard_key_page_down" msgid="8720502083731906136">"Page Down"</string>
+ <string name="keyboard_key_forward_del" msgid="1391451334716490176">"Delete"</string>
+ <string name="keyboard_key_move_home" msgid="2765693292069487486">"Home"</string>
+ <string name="keyboard_key_move_end" msgid="5901174332047975247">"End"</string>
+ <string name="keyboard_key_insert" msgid="8530501581636082614">"Insert"</string>
+ <string name="keyboard_key_num_lock" msgid="5052537581246772117">"Num Lock"</string>
+ <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"Numpad <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"Sistema"</string>
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Início"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Recentes"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Voltar"</string>
+ <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Notificações"</string>
+ <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"Atalhos do teclado"</string>
+ <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"Alterar o método de entrada"</string>
+ <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"Aplicativos"</string>
+ <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"Assistente"</string>
+ <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"Navegador"</string>
+ <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"Contatos"</string>
+ <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"E-mail"</string>
+ <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"Mensagens instantâneas"</string>
+ <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"Música"</string>
+ <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+ <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"Agenda"</string>
<string name="tuner_full_zen_title" msgid="4540823317772234308">"Mostrar com controles de volume"</string>
<string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Não perturbe"</string>
<string name="volume_dnd_silent" msgid="4363882330723050727">"Atalho de botões de volume"</string>
@@ -559,4 +596,14 @@
<string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Mover para cima"</string>
<string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Mover para a esquerda"</string>
<string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Mover para a direita"</string>
+ <string name="forced_resizable_info_text" msgid="7591061837558867999">"É possível que o app não funcione com várias janelas"</string>
+ <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"Posição <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>. Toque duas vezes para editar."</string>
+ <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. Toque duas vezes para adicionar."</string>
+ <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"Posição <xliff:g id="POSITION">%1$d</xliff:g>. Toque duas vezes para selecionar."</string>
+ <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"Move <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"Remove <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="TILE_NAME">%1$s</xliff:g> é adicionado à posição <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+ <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"<xliff:g id="TILE_NAME">%1$s</xliff:g> é removido"</string>
+ <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="TILE_NAME">%1$s</xliff:g> movido para a posição <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+ <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Editor de configurações rápidas."</string>
</resources>
diff --git a/packages/SystemUI/res/values-pt/strings_tv.xml b/packages/SystemUI/res/values-pt/strings_tv.xml
index 6061af3..0827f9c7 100644
--- a/packages/SystemUI/res/values-pt/strings_tv.xml
+++ b/packages/SystemUI/res/values-pt/strings_tv.xml
@@ -26,6 +26,5 @@
<string name="pip_hold_home" msgid="340086535668778109">"Mantenha "<b>"INÍCIO"</b>" pressionado para controlar o PIP"</string>
<string name="pip_onboarding_description" msgid="2882896641362814195">"Mantenha a tecla \"HOME\" pressionada para controlar o PIP"</string>
<string name="pip_onboarding_button" msgid="3957426748484904611">"Entendi"</string>
- <!-- no translation found for recents_tv_dismiss (3555093879593377731) -->
- <skip />
+ <string name="recents_tv_dismiss" msgid="3555093879593377731">"Dispensar"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index 5f71c41..0e818c4 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -169,6 +169,8 @@
<string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Închideți <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> a fost eliminată."</string>
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Toate aplicațiile recente au fost închise."</string>
+ <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+ <skip />
<string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Se inițiază <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
<string name="accessibility_notification_dismissed" msgid="854211387186306927">"Notificarea a fost închisă."</string>
@@ -237,8 +239,7 @@
<string name="gps_notification_found_text" msgid="4619274244146446464">"Locație setată prin GPS"</string>
<string name="accessibility_location_active" msgid="2427290146138169014">"Solicitări locație active"</string>
<string name="accessibility_clear_all" msgid="5235938559247164925">"Ștergeți toate notificările."</string>
- <!-- no translation found for notification_group_overflow_indicator (1863231301642314183) -->
- <skip />
+ <string name="notification_group_overflow_indicator" msgid="1863231301642314183">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string>
<string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"Setări pentru notificări"</string>
<string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"Setări <xliff:g id="APP_NAME">%s</xliff:g>"</string>
<string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Ecranul se va roti în mod automat."</string>
@@ -311,8 +312,7 @@
<string name="recents_search_bar_label" msgid="8074997400187836677">"căutare"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g> nu a putut porni."</string>
<string name="recents_launch_disabled_message" msgid="1624523193008871793">"Aplicația <xliff:g id="APP">%s</xliff:g> este dezactivată în modul sigur."</string>
- <string name="recents_history_button_label" msgid="5153358867807604821">"Istoric"</string>
- <string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Ștergeți"</string>
+ <string name="recents_stack_action_button_label" msgid="6593727103310426253">"Ștergeți-le pe toate"</string>
<string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"Această aplicație nu acceptă ferestre multiple"</string>
<string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"Aplicația nu acceptă ferestre multiple"</string>
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Divizare pe orizontală"</string>
@@ -481,8 +481,7 @@
<string name="notification_importance_max" msgid="5806278962376556491">"Apar în partea de sus a listei cu notificări, se afișează pentru scurt timp pe ecran și se permite un sunet"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Mai multe setări"</string>
<string name="notification_done" msgid="5279426047273930175">"Terminat"</string>
- <!-- no translation found for notification_gear_accessibility (94429150213089611) -->
- <skip />
+ <string name="notification_gear_accessibility" msgid="94429150213089611">"Opțiuni privind notificările pentru <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="color_and_appearance" msgid="1254323855964993144">"Culoare și aspect"</string>
<string name="night_mode" msgid="3540405868248625488">"Modul Noapte"</string>
<string name="calibrate_display" msgid="5974642573432039217">"Calibrați afișarea"</string>
@@ -502,10 +501,60 @@
<string name="battery_detail_charging_summary" msgid="1279095653533044008">"Economisirea bateriei nu este disponibilă pe durata încărcării"</string>
<string name="battery_detail_switch_title" msgid="6285872470260795421">"Economisirea bateriei"</string>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"Reduce performanța și datele de fundal"</string>
+ <string name="keyboard_key_button_template" msgid="6230056639734377300">"Butonul <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="keyboard_key_home" msgid="2243500072071305073">"La început"</string>
+ <string name="keyboard_key_back" msgid="2337450286042721351">"Înapoi"</string>
+ <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"În sus"</string>
+ <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"În jos"</string>
+ <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"La stânga"</string>
+ <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"La dreapta"</string>
+ <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"În centru"</string>
+ <string name="keyboard_key_tab" msgid="3871485650463164476">"Tab"</string>
+ <string name="keyboard_key_space" msgid="2499861316311153293">"Spațiu"</string>
+ <string name="keyboard_key_enter" msgid="5739632123216118137">"Enter"</string>
+ <string name="keyboard_key_backspace" msgid="1559580097512385854">"Backspace"</string>
+ <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"Redați/Întrerupeți"</string>
+ <string name="keyboard_key_media_stop" msgid="2859963958595908962">"Opriți"</string>
+ <string name="keyboard_key_media_next" msgid="1894394911630345607">"Înainte"</string>
+ <string name="keyboard_key_media_previous" msgid="4256072387192967261">"Înapoi"</string>
+ <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"Derulați înapoi"</string>
+ <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"Derulați rapid înainte"</string>
+ <string name="keyboard_key_page_up" msgid="5654098530106845603">"O pagină mai sus"</string>
+ <string name="keyboard_key_page_down" msgid="8720502083731906136">"O pagină mai jos"</string>
+ <string name="keyboard_key_forward_del" msgid="1391451334716490176">"Ștergeți"</string>
+ <string name="keyboard_key_move_home" msgid="2765693292069487486">"La început"</string>
+ <string name="keyboard_key_move_end" msgid="5901174332047975247">"La final"</string>
+ <string name="keyboard_key_insert" msgid="8530501581636082614">"Inserați"</string>
+ <string name="keyboard_key_num_lock" msgid="5052537581246772117">"Num Lock"</string>
+ <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"Tasta numerică <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"Sistem"</string>
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Ecran de pornire"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Recente"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Înapoi"</string>
+ <!-- no translation found for keyboard_shortcut_group_system_notifications (8366964080041773224) -->
+ <skip />
+ <!-- no translation found for keyboard_shortcut_group_system_shortcuts_helper (4892255911160332762) -->
+ <skip />
+ <!-- no translation found for keyboard_shortcut_group_system_switch_input (2334164096341310324) -->
+ <skip />
+ <!-- no translation found for keyboard_shortcut_group_applications (9129465955073449206) -->
+ <skip />
+ <!-- no translation found for keyboard_shortcut_group_applications_assist (9095441910537146013) -->
+ <skip />
+ <!-- no translation found for keyboard_shortcut_group_applications_browser (6465985474000766533) -->
+ <skip />
+ <!-- no translation found for keyboard_shortcut_group_applications_contacts (2064197111278436375) -->
+ <skip />
+ <!-- no translation found for keyboard_shortcut_group_applications_email (6257036897441939004) -->
+ <skip />
+ <!-- no translation found for keyboard_shortcut_group_applications_im (1892749399083161405) -->
+ <skip />
+ <!-- no translation found for keyboard_shortcut_group_applications_music (4775559515850922780) -->
+ <skip />
+ <!-- no translation found for keyboard_shortcut_group_applications_youtube (6555453761294723317) -->
+ <skip />
+ <!-- no translation found for keyboard_shortcut_group_applications_calendar (9043614299194991263) -->
+ <skip />
<string name="tuner_full_zen_title" msgid="4540823317772234308">"Afișează cu comenzile de volum"</string>
<string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Nu deranja"</string>
<string name="volume_dnd_silent" msgid="4363882330723050727">"Comandă rapidă din butoanele de volum"</string>
@@ -560,4 +609,14 @@
<string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Mutați în sus"</string>
<string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Mutați spre stânga"</string>
<string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Mutați spre dreapta"</string>
+ <string name="forced_resizable_info_text" msgid="7591061837558867999">"Este posibil ca aplicația să nu funcționeze cu ferestre multiple"</string>
+ <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"Poziția <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>. Atingeți de două ori pentru a edita."</string>
+ <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. Atingeți de două ori pentru a adăuga."</string>
+ <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"Poziția <xliff:g id="POSITION">%1$d</xliff:g>. Atingeți de două ori pentru a selecta."</string>
+ <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"Mutați <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"Eliminați <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"Caseta <xliff:g id="TILE_NAME">%1$s</xliff:g> este adăugată pe poziția <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+ <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"Caseta <xliff:g id="TILE_NAME">%1$s</xliff:g> este eliminată"</string>
+ <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"Caseta <xliff:g id="TILE_NAME">%1$s</xliff:g> a fost mutată pe poziția <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+ <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Editorul pentru setări rapide."</string>
</resources>
diff --git a/packages/SystemUI/res/values-ro/strings_tv.xml b/packages/SystemUI/res/values-ro/strings_tv.xml
index fcbfd07..9ef90dd 100644
--- a/packages/SystemUI/res/values-ro/strings_tv.xml
+++ b/packages/SystemUI/res/values-ro/strings_tv.xml
@@ -26,6 +26,5 @@
<string name="pip_hold_home" msgid="340086535668778109">"Apăsați lung "<b>"ACASĂ"</b>" pentru a controla PIP"</string>
<string name="pip_onboarding_description" msgid="2882896641362814195">"Apăsați lung butonul ECRAN DE PORNIRE pentru a controla PIP"</string>
<string name="pip_onboarding_button" msgid="3957426748484904611">"Am înțeles"</string>
- <!-- no translation found for recents_tv_dismiss (3555093879593377731) -->
- <skip />
+ <string name="recents_tv_dismiss" msgid="3555093879593377731">"Închideți"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index ffb0a73..1baa67d 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -170,6 +170,8 @@
<string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Удаление приложения <xliff:g id="APP">%s</xliff:g> из списка."</string>
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"Приложение \"<xliff:g id="APP">%s</xliff:g>\" удалено из списка."</string>
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Все недавние приложения закрыты."</string>
+ <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+ <skip />
<string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Запуск приложения <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
<string name="accessibility_notification_dismissed" msgid="854211387186306927">"Уведомление закрыто"</string>
@@ -238,8 +240,7 @@
<string name="gps_notification_found_text" msgid="4619274244146446464">"Координаты по GPS"</string>
<string name="accessibility_location_active" msgid="2427290146138169014">"Есть активные запросы на определение местоположения"</string>
<string name="accessibility_clear_all" msgid="5235938559247164925">"Удалить все уведомления"</string>
- <!-- no translation found for notification_group_overflow_indicator (1863231301642314183) -->
- <skip />
+ <string name="notification_group_overflow_indicator" msgid="1863231301642314183">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string>
<string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"Настройки уведомлений"</string>
<string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"Настройки приложения \"<xliff:g id="APP_NAME">%s</xliff:g>\""</string>
<string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Экран будет поворачиваться автоматически."</string>
@@ -312,8 +313,7 @@
<string name="recents_search_bar_label" msgid="8074997400187836677">"поиск"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"Не удалось запустить приложение \"<xliff:g id="APP">%s</xliff:g>\""</string>
<string name="recents_launch_disabled_message" msgid="1624523193008871793">"Приложение \"<xliff:g id="APP">%s</xliff:g>\" отключено в безопасном режиме."</string>
- <string name="recents_history_button_label" msgid="5153358867807604821">"Журнал"</string>
- <string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Очистить"</string>
+ <string name="recents_stack_action_button_label" msgid="6593727103310426253">"Очистить все"</string>
<string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"Приложение не поддерживает многооконный режим"</string>
<string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"Приложение не поддерживает многооконный режим"</string>
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Разделить по горизонтали"</string>
@@ -482,8 +482,7 @@
<string name="notification_importance_max" msgid="5806278962376556491">"Показывать со звуком в начале списка уведомлений и поверх всех окон"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Другие настройки"</string>
<string name="notification_done" msgid="5279426047273930175">"Готово"</string>
- <!-- no translation found for notification_gear_accessibility (94429150213089611) -->
- <skip />
+ <string name="notification_gear_accessibility" msgid="94429150213089611">"Управление уведомлениями (<xliff:g id="APP_NAME">%1$s</xliff:g>)"</string>
<string name="color_and_appearance" msgid="1254323855964993144">"Цвета и стиль"</string>
<string name="night_mode" msgid="3540405868248625488">"Ночной режим"</string>
<string name="calibrate_display" msgid="5974642573432039217">"Калибровка дисплея"</string>
@@ -503,10 +502,60 @@
<string name="battery_detail_charging_summary" msgid="1279095653533044008">"Режим энергосбережения нельзя включить во время зарядки"</string>
<string name="battery_detail_switch_title" msgid="6285872470260795421">"Режим энергосбережения"</string>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"Ограничивает производительность и фоновую передачу данных"</string>
+ <string name="keyboard_key_button_template" msgid="6230056639734377300">"Кнопка <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="keyboard_key_home" msgid="2243500072071305073">"Главный экран"</string>
+ <string name="keyboard_key_back" msgid="2337450286042721351">"Назад"</string>
+ <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"Стрелка вверх"</string>
+ <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"Стрелка вниз"</string>
+ <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"Стрелка влево"</string>
+ <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"Стрелка вправо"</string>
+ <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"Центральная стрелка"</string>
+ <string name="keyboard_key_tab" msgid="3871485650463164476">"Tab"</string>
+ <string name="keyboard_key_space" msgid="2499861316311153293">"Пробел"</string>
+ <string name="keyboard_key_enter" msgid="5739632123216118137">"Ввод"</string>
+ <string name="keyboard_key_backspace" msgid="1559580097512385854">"Backspace"</string>
+ <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"Воспроизведение/пауза"</string>
+ <string name="keyboard_key_media_stop" msgid="2859963958595908962">"Стоп"</string>
+ <string name="keyboard_key_media_next" msgid="1894394911630345607">"Следующий трек"</string>
+ <string name="keyboard_key_media_previous" msgid="4256072387192967261">"Предыдущий трек"</string>
+ <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"Перемотка назад"</string>
+ <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"Перемотка вперед"</string>
+ <string name="keyboard_key_page_up" msgid="5654098530106845603">"Page Up"</string>
+ <string name="keyboard_key_page_down" msgid="8720502083731906136">"Page Down"</string>
+ <string name="keyboard_key_forward_del" msgid="1391451334716490176">"Delete"</string>
+ <string name="keyboard_key_move_home" msgid="2765693292069487486">"Home"</string>
+ <string name="keyboard_key_move_end" msgid="5901174332047975247">"End"</string>
+ <string name="keyboard_key_insert" msgid="8530501581636082614">"Insert"</string>
+ <string name="keyboard_key_num_lock" msgid="5052537581246772117">"Num Lock"</string>
+ <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"<xliff:g id="NAME">%1$s</xliff:g> на цифровой панели"</string>
<string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"Система"</string>
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Главный экран"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Недавние"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Назад"</string>
+ <!-- no translation found for keyboard_shortcut_group_system_notifications (8366964080041773224) -->
+ <skip />
+ <!-- no translation found for keyboard_shortcut_group_system_shortcuts_helper (4892255911160332762) -->
+ <skip />
+ <!-- no translation found for keyboard_shortcut_group_system_switch_input (2334164096341310324) -->
+ <skip />
+ <!-- no translation found for keyboard_shortcut_group_applications (9129465955073449206) -->
+ <skip />
+ <!-- no translation found for keyboard_shortcut_group_applications_assist (9095441910537146013) -->
+ <skip />
+ <!-- no translation found for keyboard_shortcut_group_applications_browser (6465985474000766533) -->
+ <skip />
+ <!-- no translation found for keyboard_shortcut_group_applications_contacts (2064197111278436375) -->
+ <skip />
+ <!-- no translation found for keyboard_shortcut_group_applications_email (6257036897441939004) -->
+ <skip />
+ <!-- no translation found for keyboard_shortcut_group_applications_im (1892749399083161405) -->
+ <skip />
+ <!-- no translation found for keyboard_shortcut_group_applications_music (4775559515850922780) -->
+ <skip />
+ <!-- no translation found for keyboard_shortcut_group_applications_youtube (6555453761294723317) -->
+ <skip />
+ <!-- no translation found for keyboard_shortcut_group_applications_calendar (9043614299194991263) -->
+ <skip />
<string name="tuner_full_zen_title" msgid="4540823317772234308">"Показывать при нажатии кнопок регулировки громкости"</string>
<string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Не беспокоить"</string>
<string name="volume_dnd_silent" msgid="4363882330723050727">"Кнопки регулировки громкости"</string>
@@ -561,4 +610,14 @@
<string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Поднять"</string>
<string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Сдвинуть влево"</string>
<string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Сдвинуть вправо"</string>
+ <string name="forced_resizable_info_text" msgid="7591061837558867999">"Приложение не поддерживает многооконный режим"</string>
+ <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"Позиция <xliff:g id="POSITION">%1$d</xliff:g>, кнопка \"<xliff:g id="TILE_NAME">%2$s</xliff:g>\". Чтобы изменить, нажмите дважды."</string>
+ <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"Кнопка \"<xliff:g id="TILE_NAME">%1$s</xliff:g>\". Чтобы добавить, нажмите дважды."</string>
+ <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"Позиция <xliff:g id="POSITION">%1$d</xliff:g>. Чтобы выбрать, нажмите дважды."</string>
+ <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"Переместить кнопку \"<xliff:g id="TILE_NAME">%1$s</xliff:g>\""</string>
+ <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"Удалить кнопку \"<xliff:g id="TILE_NAME">%1$s</xliff:g>\""</string>
+ <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"Кнопка \"<xliff:g id="TILE_NAME">%1$s</xliff:g>\" теперь занимает позицию <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+ <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"Кнопка \"<xliff:g id="TILE_NAME">%1$s</xliff:g>\" удалена"</string>
+ <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"Кнопка \"<xliff:g id="TILE_NAME">%1$s</xliff:g>\" теперь занимает позицию <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+ <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Редактор быстрых настроек."</string>
</resources>
diff --git a/packages/SystemUI/res/values-ru/strings_tv.xml b/packages/SystemUI/res/values-ru/strings_tv.xml
index 309ce73..027cb1f 100644
--- a/packages/SystemUI/res/values-ru/strings_tv.xml
+++ b/packages/SystemUI/res/values-ru/strings_tv.xml
@@ -26,6 +26,5 @@
<string name="pip_hold_home" msgid="340086535668778109">"Управляйте кадром в кадре, удерживая кнопку "<b>"ГЛАВНАЯ"</b></string>
<string name="pip_onboarding_description" msgid="2882896641362814195">"Управляйте режимом \"Кадр в кадре\", удерживая кнопку ГЛАВНАЯ"</string>
<string name="pip_onboarding_button" msgid="3957426748484904611">"ОК"</string>
- <!-- no translation found for recents_tv_dismiss (3555093879593377731) -->
- <skip />
+ <string name="recents_tv_dismiss" msgid="3555093879593377731">"Закрыть"</string>
</resources>
diff --git a/packages/SystemUI/res/values-si-rLK/strings.xml b/packages/SystemUI/res/values-si-rLK/strings.xml
index 84c2f1b..5a2f849 100644
--- a/packages/SystemUI/res/values-si-rLK/strings.xml
+++ b/packages/SystemUI/res/values-si-rLK/strings.xml
@@ -168,6 +168,8 @@
<string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"<xliff:g id="APP">%s</xliff:g> ඉවතලන්න."</string>
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> අස් කර ඇත."</string>
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"සියලුම මෑත යෙඳුම් අස් කරන ලදි."</string>
+ <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+ <skip />
<string name="accessibility_recents_item_launched" msgid="7616039892382525203">"<xliff:g id="APP">%s</xliff:g> ආරම්භ කරමින්."</string>
<string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
<string name="accessibility_notification_dismissed" msgid="854211387186306927">"දැනුම්දීම නිෂ්ප්රභා කරඇත."</string>
@@ -236,8 +238,7 @@
<string name="gps_notification_found_text" msgid="4619274244146446464">"GPS මඟින් ස්ථානය සකසා ඇත"</string>
<string name="accessibility_location_active" msgid="2427290146138169014">"පිහිටීම් ඉල්ලීම් සක්රියයි"</string>
<string name="accessibility_clear_all" msgid="5235938559247164925">"සියලු දැනුම්දීම් හිස් කරන්න."</string>
- <!-- no translation found for notification_group_overflow_indicator (1863231301642314183) -->
- <skip />
+ <string name="notification_group_overflow_indicator" msgid="1863231301642314183">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string>
<string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"දැනුම්දීම් සැකසීම්"</string>
<string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"<xliff:g id="APP_NAME">%s</xliff:g> සැකසීම්"</string>
<string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"තිරය ස්වයංක්රීයව කරකැවේ."</string>
@@ -310,8 +311,7 @@
<string name="recents_search_bar_label" msgid="8074997400187836677">"සෙවීම"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g> ආරම්භ කළ නොහැක."</string>
<string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g> ආරක්ෂිත ප්රකාරය තුළ අබලයි."</string>
- <string name="recents_history_button_label" msgid="5153358867807604821">"ඉතිහාසය"</string>
- <string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"හිස් කරන්න"</string>
+ <string name="recents_stack_action_button_label" msgid="6593727103310426253">"සියල්ල හිස් කරන්න"</string>
<string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"මෙම යෙදුම බහු-කවුළුව සඳහා සහාය නොදක්වයි"</string>
<string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"යෙදුම බහු-කවුළුව සඳහා සහාය නොදක්වයි"</string>
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"තිරස්ව වෙන් කරන්න"</string>
@@ -480,8 +480,7 @@
<string name="notification_importance_max" msgid="5806278962376556491">"දැනුම්දීම් ලැයිස්තුවෙහි ඉහළින්ම පෙන්වන්න, තිරයට එබිකම් කර ශබ්දයට ඉඩ දෙන්න"</string>
<string name="notification_more_settings" msgid="816306283396553571">"තව සැකසීම්"</string>
<string name="notification_done" msgid="5279426047273930175">"නිමයි"</string>
- <!-- no translation found for notification_gear_accessibility (94429150213089611) -->
- <skip />
+ <string name="notification_gear_accessibility" msgid="94429150213089611">"<xliff:g id="APP_NAME">%1$s</xliff:g> දැනුම්දීම් පාලන"</string>
<string name="color_and_appearance" msgid="1254323855964993144">"වර්ණය සහ පෙනුම"</string>
<string name="night_mode" msgid="3540405868248625488">"රාත්රී ප්රකාරය"</string>
<string name="calibrate_display" msgid="5974642573432039217">"සංදර්ශකය ක්රමාංකනය කරන්න"</string>
@@ -501,10 +500,48 @@
<string name="battery_detail_charging_summary" msgid="1279095653533044008">"ආරෝපණය අතරතුර බැටරි සුරැකුම ලබා ගත නොහැකිය."</string>
<string name="battery_detail_switch_title" msgid="6285872470260795421">"බැටරි සුරැකුම"</string>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"ක්රියාකාරිත්වය සහ පසුබිම් දත්ත අඩු කරන්න"</string>
+ <string name="keyboard_key_button_template" msgid="6230056639734377300">"<xliff:g id="NAME">%1$s</xliff:g> බොත්තම"</string>
+ <string name="keyboard_key_home" msgid="2243500072071305073">"Home යතුර"</string>
+ <string name="keyboard_key_back" msgid="2337450286042721351">"ආපසු"</string>
+ <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"උඩු"</string>
+ <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"යටි"</string>
+ <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"වම්"</string>
+ <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"දකුණු"</string>
+ <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"මැද"</string>
+ <string name="keyboard_key_tab" msgid="3871485650463164476">"Tab යතුර"</string>
+ <string name="keyboard_key_space" msgid="2499861316311153293">"ඉඩ යතුර"</string>
+ <string name="keyboard_key_enter" msgid="5739632123216118137">"Enter යතුර"</string>
+ <string name="keyboard_key_backspace" msgid="1559580097512385854">"Backspace යතුර"</string>
+ <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"ධාවනය කරන්න/විරාම කරන්න"</string>
+ <string name="keyboard_key_media_stop" msgid="2859963958595908962">"නතර කරන්න"</string>
+ <string name="keyboard_key_media_next" msgid="1894394911630345607">"ඊළඟ"</string>
+ <string name="keyboard_key_media_previous" msgid="4256072387192967261">"පෙර"</string>
+ <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"නැවත ඔතන්න"</string>
+ <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"වේගයෙන් ඉදිරියට යන"</string>
+ <string name="keyboard_key_page_up" msgid="5654098530106845603">"Page Up යතුර"</string>
+ <string name="keyboard_key_page_down" msgid="8720502083731906136">"Page Down යතුර"</string>
+ <string name="keyboard_key_forward_del" msgid="1391451334716490176">"Delete යතුර"</string>
+ <string name="keyboard_key_move_home" msgid="2765693292069487486">"Home යතුර"</string>
+ <string name="keyboard_key_move_end" msgid="5901174332047975247">"End යතුර"</string>
+ <string name="keyboard_key_insert" msgid="8530501581636082614">"Insert යතුර"</string>
+ <string name="keyboard_key_num_lock" msgid="5052537581246772117">"Num Lock යතුර"</string>
+ <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"<xliff:g id="NAME">%1$s</xliff:g> අංක පෑඩය"</string>
<string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"පද්ධතිය"</string>
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"මුල් පිටුව"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"මෑත"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"ආපසු"</string>
+ <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"දැනුම්දීම්"</string>
+ <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"යතුරු පුවරු කෙටිමං"</string>
+ <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"ආදාන ක්රමය මාරු කිරීම"</string>
+ <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"යෙදුම්"</string>
+ <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"සහාය"</string>
+ <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"බ්රවුසරය"</string>
+ <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"සම්බන්ධතා"</string>
+ <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"ඊ-තැපෑල"</string>
+ <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"IM"</string>
+ <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"සංගීතය"</string>
+ <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+ <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"දින දර්ශනය"</string>
<string name="tuner_full_zen_title" msgid="4540823317772234308">"හඩ පරිමා පාලන සහිතව පෙන්වන්න"</string>
<string name="volume_and_do_not_disturb" msgid="3373784330208603030">"බාධා නොකරන්න"</string>
<string name="volume_dnd_silent" msgid="4363882330723050727">"හඩ පරිමා බොත්තම් කෙටිමග"</string>
@@ -540,8 +577,7 @@
<string name="select_keycode" msgid="7413765103381924584">"යතුරු පුවරු බොත්තම තෝරන්න"</string>
<string name="preview" msgid="9077832302472282938">"පෙරදසුන"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"ටයිල් එක් කිරීමට අදින්න"</string>
- <!-- no translation found for drag_to_remove_tiles (3361212377437088062) -->
- <skip />
+ <string name="drag_to_remove_tiles" msgid="3361212377437088062">"ඉවත් කිරීමට මෙතැනට අදින්න"</string>
<string name="qs_edit" msgid="2232596095725105230">"සංස්කරණය කරන්න"</string>
<string name="tuner_time" msgid="6572217313285536011">"වේලාව"</string>
<string-array name="clock_options">
@@ -560,4 +596,14 @@
<string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"ඉහළට ගෙන යන්න"</string>
<string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"වමට ගෙන යන්න"</string>
<string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"දකුණට ගෙන යන්න"</string>
+ <string name="forced_resizable_info_text" msgid="7591061837558867999">"යෙදුම බහු-කවුළුව සමඟ ක්රියා නොකළ හැකිය."</string>
+ <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"ස්ථානය <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>. වෙනස් කිරීමට දෙවරක් තට්ටු කරන්න."</string>
+ <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. එක් කිරීමට දෙවරක් තට්ටු කරන්න."</string>
+ <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"ස්ථානය <xliff:g id="POSITION">%1$d</xliff:g>. තෝරා ගැනීමට දෙවරක් තට්ටු කරන්න."</string>
+ <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"<xliff:g id="TILE_NAME">%1$s</xliff:g> ගෙන යන්න"</string>
+ <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"<xliff:g id="TILE_NAME">%1$s</xliff:g> ඉවත් කරන්න"</string>
+ <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="TILE_NAME">%1$s</xliff:g> <xliff:g id="POSITION">%2$d</xliff:g> වන ස්ථානයට එක් කරන ලදි"</string>
+ <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"<xliff:g id="TILE_NAME">%1$s</xliff:g> ඉවත් කරන ලදි"</string>
+ <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="TILE_NAME">%1$s</xliff:g> <xliff:g id="POSITION">%2$d</xliff:g> වන ස්ථානයට ගෙන යන ලදි"</string>
+ <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"ඉක්මන් සැකසුම් සංස්කාරකය."</string>
</resources>
diff --git a/packages/SystemUI/res/values-si-rLK/strings_tv.xml b/packages/SystemUI/res/values-si-rLK/strings_tv.xml
index f3e95a1..3380754 100644
--- a/packages/SystemUI/res/values-si-rLK/strings_tv.xml
+++ b/packages/SystemUI/res/values-si-rLK/strings_tv.xml
@@ -26,6 +26,5 @@
<string name="pip_hold_home" msgid="340086535668778109">"PIP පාලනයට "<b>"HOME"</b>" අල්ලාගන්න"</string>
<string name="pip_onboarding_description" msgid="2882896641362814195">"PIP පාලනය කිරීමට HOME බොත්තම ඔබා අල්ලාගෙන සිටින්න"</string>
<string name="pip_onboarding_button" msgid="3957426748484904611">"හරි, තේරුණා"</string>
- <!-- no translation found for recents_tv_dismiss (3555093879593377731) -->
- <skip />
+ <string name="recents_tv_dismiss" msgid="3555093879593377731">"අස් කරන්න"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index e53b037..9468fcf 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -170,6 +170,8 @@
<string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Zrušiť aplikáciu <xliff:g id="APP">%s</xliff:g>"</string>
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"Aplikácia <xliff:g id="APP">%s</xliff:g> bola zrušená."</string>
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Všetky nedávne aplikácie boli odmietnuté."</string>
+ <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+ <skip />
<string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Spúšťa sa aplikácia <xliff:g id="APP">%s</xliff:g>"</string>
<string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
<string name="accessibility_notification_dismissed" msgid="854211387186306927">"Upozornenie bolo zrušené."</string>
@@ -238,8 +240,7 @@
<string name="gps_notification_found_text" msgid="4619274244146446464">"Poloha nastavená pomocou GPS"</string>
<string name="accessibility_location_active" msgid="2427290146138169014">"Žiadosti o polohu sú aktívne"</string>
<string name="accessibility_clear_all" msgid="5235938559247164925">"Vymazať všetky upozornenia."</string>
- <!-- no translation found for notification_group_overflow_indicator (1863231301642314183) -->
- <skip />
+ <string name="notification_group_overflow_indicator" msgid="1863231301642314183">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string>
<string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"Nastavenia upozornení"</string>
<string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"Nastavenia aplikácie <xliff:g id="APP_NAME">%s</xliff:g>"</string>
<string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Obrazovka sa automaticky otočí."</string>
@@ -312,8 +313,7 @@
<string name="recents_search_bar_label" msgid="8074997400187836677">"hľadať"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"Aplikáciu <xliff:g id="APP">%s</xliff:g> sa nepodarilo spustiť"</string>
<string name="recents_launch_disabled_message" msgid="1624523193008871793">"Aplikácia <xliff:g id="APP">%s</xliff:g> je v núdzovom režime zakázaná."</string>
- <string name="recents_history_button_label" msgid="5153358867807604821">"História"</string>
- <string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Vymazať"</string>
+ <string name="recents_stack_action_button_label" msgid="6593727103310426253">"Vymazať všetko"</string>
<string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"Táto aplikácia nepodporuje režim viacerých okien"</string>
<string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"Aplikácia nepodporuje režim viacerých okien"</string>
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Rozdeliť vodorovné"</string>
@@ -482,8 +482,7 @@
<string name="notification_importance_max" msgid="5806278962376556491">"Zobrazovať v hornej časti zoznamu upozornení, zobrazovať cez obrazovku a povoliť zvukový signál"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Ďalšie nastavenia"</string>
<string name="notification_done" msgid="5279426047273930175">"Hotovo"</string>
- <!-- no translation found for notification_gear_accessibility (94429150213089611) -->
- <skip />
+ <string name="notification_gear_accessibility" msgid="94429150213089611">"Ovládacie prvky pre upozornenia z aplikácie <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="color_and_appearance" msgid="1254323855964993144">"Farba a vzhľad"</string>
<string name="night_mode" msgid="3540405868248625488">"Nočný režim"</string>
<string name="calibrate_display" msgid="5974642573432039217">"Kalibrovať obrazovku"</string>
@@ -503,10 +502,48 @@
<string name="battery_detail_charging_summary" msgid="1279095653533044008">"Počas nabíjania nie je Šetrič batérie k dispozícii"</string>
<string name="battery_detail_switch_title" msgid="6285872470260795421">"Šetrič batérie"</string>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"Obmedzí výkonnosť a údaje na pozadí"</string>
+ <string name="keyboard_key_button_template" msgid="6230056639734377300">"Tlačidlo <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="keyboard_key_home" msgid="2243500072071305073">"Domov"</string>
+ <string name="keyboard_key_back" msgid="2337450286042721351">"Späť"</string>
+ <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"Nahor"</string>
+ <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"Nadol"</string>
+ <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"Doľava"</string>
+ <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"Doprava"</string>
+ <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"Do stredu"</string>
+ <string name="keyboard_key_tab" msgid="3871485650463164476">"Tabulátor"</string>
+ <string name="keyboard_key_space" msgid="2499861316311153293">"Medzerník"</string>
+ <string name="keyboard_key_enter" msgid="5739632123216118137">"Enter"</string>
+ <string name="keyboard_key_backspace" msgid="1559580097512385854">"Backspace"</string>
+ <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"Prehrať/pozastaviť"</string>
+ <string name="keyboard_key_media_stop" msgid="2859963958595908962">"Zastaviť"</string>
+ <string name="keyboard_key_media_next" msgid="1894394911630345607">"Nasledujúce"</string>
+ <string name="keyboard_key_media_previous" msgid="4256072387192967261">"Predchádzajúce"</string>
+ <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"Pretočiť späť"</string>
+ <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"Pretočiť dopredu"</string>
+ <string name="keyboard_key_page_up" msgid="5654098530106845603">"Posunúť o stranu vyššie"</string>
+ <string name="keyboard_key_page_down" msgid="8720502083731906136">"Posunúť o stranu nižšie"</string>
+ <string name="keyboard_key_forward_del" msgid="1391451334716490176">"Odstrániť"</string>
+ <string name="keyboard_key_move_home" msgid="2765693292069487486">"Domov"</string>
+ <string name="keyboard_key_move_end" msgid="5901174332047975247">"Ukončiť"</string>
+ <string name="keyboard_key_insert" msgid="8530501581636082614">"Vložiť"</string>
+ <string name="keyboard_key_num_lock" msgid="5052537581246772117">"Num Lock"</string>
+ <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"Číselná klávesnica <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"Systém"</string>
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Domovská stránka"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Nedávne"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Späť"</string>
+ <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Upozornenia"</string>
+ <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"Klávesové skratky"</string>
+ <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"Prepnúť metódu vstupu"</string>
+ <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"Aplikácie"</string>
+ <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"Pomocná aplikácia"</string>
+ <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"Prehliadač"</string>
+ <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"Kontakty"</string>
+ <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"E-mail"</string>
+ <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"Okamžité správy"</string>
+ <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"Hudba"</string>
+ <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+ <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"Kalendár"</string>
<string name="tuner_full_zen_title" msgid="4540823317772234308">"Zobrazovať s ovládacími prvkami hlasitosti"</string>
<string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Nerušiť"</string>
<string name="volume_dnd_silent" msgid="4363882330723050727">"Skratka tlačidiel hlasitosti"</string>
@@ -561,4 +598,14 @@
<string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Posunúť nahor"</string>
<string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Posunúť doľava"</string>
<string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Posunúť doprava"</string>
+ <string name="forced_resizable_info_text" msgid="7591061837558867999">"Aplikácia nemusí fungovať v režime viacerých okien"</string>
+ <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"Pozícia <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>. Upravíte ju dvojitým klepnutím."</string>
+ <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. Pridáte ju dvojitým klepnutím."</string>
+ <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"Pozícia <xliff:g id="POSITION">%1$d</xliff:g>. Vyberiete ju dvojitým klepnutím."</string>
+ <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"Presunúť dlaždicu <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"Odstrániť dlaždicu <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"Dlaždica <xliff:g id="TILE_NAME">%1$s</xliff:g> bola pridaná na pozíciu <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+ <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"Dlaždica <xliff:g id="TILE_NAME">%1$s</xliff:g> bola odstránená"</string>
+ <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"Dlaždica <xliff:g id="TILE_NAME">%1$s</xliff:g> bola presunutá na pozíciu <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+ <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Editor rýchlych nastavení"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sk/strings_tv.xml b/packages/SystemUI/res/values-sk/strings_tv.xml
index 64fa0e8..cc48e07 100644
--- a/packages/SystemUI/res/values-sk/strings_tv.xml
+++ b/packages/SystemUI/res/values-sk/strings_tv.xml
@@ -26,6 +26,5 @@
<string name="pip_hold_home" msgid="340086535668778109">"Režim PIP ovládajte pomocou tlačidla "<b>"PLOCHA"</b></string>
<string name="pip_onboarding_description" msgid="2882896641362814195">"Režim PIP ovládajte stlačením a podržaním tlačidla PLOCHA"</string>
<string name="pip_onboarding_button" msgid="3957426748484904611">"Dobre"</string>
- <!-- no translation found for recents_tv_dismiss (3555093879593377731) -->
- <skip />
+ <string name="recents_tv_dismiss" msgid="3555093879593377731">"Odmietnuť"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index 8cff73b1..c5a43f9 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -170,6 +170,8 @@
<string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Opusti aplikacijo <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"Aplikacija <xliff:g id="APP">%s</xliff:g> je bila odstranjena."</string>
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Vse nedavne aplikacije so bile opuščene."</string>
+ <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+ <skip />
<string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Zaganjanje aplikacije <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
<string name="accessibility_notification_dismissed" msgid="854211387186306927">"Obvestilo je bilo odstranjeno."</string>
@@ -238,8 +240,7 @@
<string name="gps_notification_found_text" msgid="4619274244146446464">"Lokacija nastavljena z GPS-om"</string>
<string name="accessibility_location_active" msgid="2427290146138169014">"Aktivne zahteve za lokacijo"</string>
<string name="accessibility_clear_all" msgid="5235938559247164925">"Izbriši vsa obvestila."</string>
- <!-- no translation found for notification_group_overflow_indicator (1863231301642314183) -->
- <skip />
+ <string name="notification_group_overflow_indicator" msgid="1863231301642314183">"in <xliff:g id="NUMBER">%s</xliff:g>"</string>
<string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"Nastavitve obvestil"</string>
<string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"Nastavitve aplikacije <xliff:g id="APP_NAME">%s</xliff:g>"</string>
<string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Zaslon se bo samodejno zasukal."</string>
@@ -312,8 +313,7 @@
<string name="recents_search_bar_label" msgid="8074997400187836677">"iskanje"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"Aplikacije <xliff:g id="APP">%s</xliff:g> ni bilo mogoče zagnati."</string>
<string name="recents_launch_disabled_message" msgid="1624523193008871793">"Aplikacija <xliff:g id="APP">%s</xliff:g> je v varnem načinu onemogočena."</string>
- <string name="recents_history_button_label" msgid="5153358867807604821">"Zgodovina"</string>
- <string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Izbriši"</string>
+ <string name="recents_stack_action_button_label" msgid="6593727103310426253">"Izbriši vse"</string>
<string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"Ta aplikacija ne podpira načina z več okni"</string>
<string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"Aplikacija ne podpira načina z več okni"</string>
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Razdeli vodoravno"</string>
@@ -482,8 +482,7 @@
<string name="notification_importance_max" msgid="5806278962376556491">"Prikaži na vrhu seznama obvestil, za hip pokaži predogled na zaslonu in dovoli zvok"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Več nastavitev"</string>
<string name="notification_done" msgid="5279426047273930175">"Dokončano"</string>
- <!-- no translation found for notification_gear_accessibility (94429150213089611) -->
- <skip />
+ <string name="notification_gear_accessibility" msgid="94429150213089611">"Kontrolniki obvestil za aplikacijo <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="color_and_appearance" msgid="1254323855964993144">"Barva in videz"</string>
<string name="night_mode" msgid="3540405868248625488">"Nočni način"</string>
<string name="calibrate_display" msgid="5974642573432039217">"Umerjanje zaslona"</string>
@@ -503,10 +502,48 @@
<string name="battery_detail_charging_summary" msgid="1279095653533044008">"Varčevanje z energijo akumulatorja med polnjenjem ni na voljo"</string>
<string name="battery_detail_switch_title" msgid="6285872470260795421">"Varčevanje z energijo akumulatorja"</string>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"Omeji zmogljivost delovanja in prenos podatkov v ozadju"</string>
+ <string name="keyboard_key_button_template" msgid="6230056639734377300">"Gumb <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="keyboard_key_home" msgid="2243500072071305073">"Začetek"</string>
+ <string name="keyboard_key_back" msgid="2337450286042721351">"Nazaj"</string>
+ <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"Gor"</string>
+ <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"Dol"</string>
+ <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"Levo"</string>
+ <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"Desno"</string>
+ <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"Sredina"</string>
+ <string name="keyboard_key_tab" msgid="3871485650463164476">"Tabulatorka"</string>
+ <string name="keyboard_key_space" msgid="2499861316311153293">"Preslednica"</string>
+ <string name="keyboard_key_enter" msgid="5739632123216118137">"Vnesi"</string>
+ <string name="keyboard_key_backspace" msgid="1559580097512385854">"Premik nazaj"</string>
+ <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"Predvajaj/zaustavi"</string>
+ <string name="keyboard_key_media_stop" msgid="2859963958595908962">"Ustavi"</string>
+ <string name="keyboard_key_media_next" msgid="1894394911630345607">"Naslednji"</string>
+ <string name="keyboard_key_media_previous" msgid="4256072387192967261">"Prejšnji"</string>
+ <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"Previj nazaj"</string>
+ <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"Previj naprej"</string>
+ <string name="keyboard_key_page_up" msgid="5654098530106845603">"Stran gor"</string>
+ <string name="keyboard_key_page_down" msgid="8720502083731906136">"Stran dol"</string>
+ <string name="keyboard_key_forward_del" msgid="1391451334716490176">"Izbriši"</string>
+ <string name="keyboard_key_move_home" msgid="2765693292069487486">"Začetek"</string>
+ <string name="keyboard_key_move_end" msgid="5901174332047975247">"Konec"</string>
+ <string name="keyboard_key_insert" msgid="8530501581636082614">"Vstavi"</string>
+ <string name="keyboard_key_num_lock" msgid="5052537581246772117">"Num Lock"</string>
+ <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"Številska tipkovnica <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"Sistem"</string>
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Začetni zaslon"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Nedavni"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Nazaj"</string>
+ <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Obvestila"</string>
+ <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"Bližnjične tipke"</string>
+ <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"Preklop načina vnosa"</string>
+ <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"Aplikacije"</string>
+ <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"Pomoč"</string>
+ <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"Brskalnik"</string>
+ <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"Stiki"</string>
+ <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"E-pošta"</string>
+ <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"Neposredno sporočanje"</string>
+ <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"Glasba"</string>
+ <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+ <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"Koledar"</string>
<string name="tuner_full_zen_title" msgid="4540823317772234308">"Prikaži s kontrolniki glasnosti"</string>
<string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Ne moti"</string>
<string name="volume_dnd_silent" msgid="4363882330723050727">"Bližnjica z gumboma za glasnost"</string>
@@ -561,4 +598,14 @@
<string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Premakni navzgor"</string>
<string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Premakni levo"</string>
<string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Premakni desno"</string>
+ <string name="forced_resizable_info_text" msgid="7591061837558867999">"Aplikacija morda ne deluje v načinu z več okni"</string>
+ <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"Položaj <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>. Če želite urediti, se dvakrat dotaknite."</string>
+ <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. Če želite dodati, se dvakrat dotaknite."</string>
+ <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"Položaj: <xliff:g id="POSITION">%1$d</xliff:g>. Če želite izbrati, se dvakrat dotaknite."</string>
+ <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"Premik tega: <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"Odstranitev tega: <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="TILE_NAME">%1$s</xliff:g> je dodano na položaj <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+ <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"<xliff:g id="TILE_NAME">%1$s</xliff:g> je odstranjeno"</string>
+ <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="TILE_NAME">%1$s</xliff:g> premaknjeno na položaj <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+ <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Urejevalnik hitrih nastavitev."</string>
</resources>
diff --git a/packages/SystemUI/res/values-sl/strings_tv.xml b/packages/SystemUI/res/values-sl/strings_tv.xml
index 4d0576b..38f9e8e 100644
--- a/packages/SystemUI/res/values-sl/strings_tv.xml
+++ b/packages/SystemUI/res/values-sl/strings_tv.xml
@@ -26,6 +26,5 @@
<string name="pip_hold_home" msgid="340086535668778109">"Pridr. "<b>"HOME"</b>" za up. n. PIP"</string>
<string name="pip_onboarding_description" msgid="2882896641362814195">"Pridržite gumb HOME za upravljanje načina PIP"</string>
<string name="pip_onboarding_button" msgid="3957426748484904611">"Razumem"</string>
- <!-- no translation found for recents_tv_dismiss (3555093879593377731) -->
- <skip />
+ <string name="recents_tv_dismiss" msgid="3555093879593377731">"Opusti"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sq-rAL/strings.xml b/packages/SystemUI/res/values-sq-rAL/strings.xml
index 35b4dc7..0188e5b 100644
--- a/packages/SystemUI/res/values-sq-rAL/strings.xml
+++ b/packages/SystemUI/res/values-sq-rAL/strings.xml
@@ -168,6 +168,8 @@
<string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Largo <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> është hequr."</string>
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Të gjitha aplikacionet e fundit u larguan."</string>
+ <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+ <skip />
<string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Po nis <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
<string name="accessibility_notification_dismissed" msgid="854211387186306927">"Njoftimi është hequr."</string>
@@ -236,8 +238,7 @@
<string name="gps_notification_found_text" msgid="4619274244146446464">"Vendndodhja është caktuar nga GPS-ja"</string>
<string name="accessibility_location_active" msgid="2427290146138169014">"Kërkesat për vendodhje janë aktive"</string>
<string name="accessibility_clear_all" msgid="5235938559247164925">"Pastro të gjitha njoftimet."</string>
- <!-- no translation found for notification_group_overflow_indicator (1863231301642314183) -->
- <skip />
+ <string name="notification_group_overflow_indicator" msgid="1863231301642314183">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string>
<string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"Cilësimet e njoftimeve"</string>
<string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"Cilësimet e <xliff:g id="APP_NAME">%s</xliff:g>"</string>
<string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Ekrani do të rrotullohet automatikisht."</string>
@@ -310,8 +311,7 @@
<string name="recents_search_bar_label" msgid="8074997400187836677">"kërko"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g> nuk mundi të nisej."</string>
<string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g> është i çaktivizuar në modalitetin e sigurt."</string>
- <string name="recents_history_button_label" msgid="5153358867807604821">"Historiku"</string>
- <string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Pastro"</string>
+ <string name="recents_stack_action_button_label" msgid="6593727103310426253">"Pastroji të gjitha"</string>
<string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"Ky aplikacion nuk e mbështet modalitetin me shumë dritare"</string>
<string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"Aplikacioni nuk e mbështet modalitetin me shumë dritare"</string>
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Ndaje horizontalisht"</string>
@@ -480,8 +480,7 @@
<string name="notification_importance_max" msgid="5806278962376556491">"Shfaqi në krye të listës së njoftimeve, shfaq vështrim të shpejtë në ekran dhe lësho një tingull"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Cilësime të tjera"</string>
<string name="notification_done" msgid="5279426047273930175">"U krye"</string>
- <!-- no translation found for notification_gear_accessibility (94429150213089611) -->
- <skip />
+ <string name="notification_gear_accessibility" msgid="94429150213089611">"Kontrollet e njoftimeve të <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="color_and_appearance" msgid="1254323855964993144">"Ngjyra dhe pamja"</string>
<string name="night_mode" msgid="3540405868248625488">"Modaliteti i natës"</string>
<string name="calibrate_display" msgid="5974642573432039217">"Kalibro ekranin"</string>
@@ -501,10 +500,48 @@
<string name="battery_detail_charging_summary" msgid="1279095653533044008">"\"Kursyesi i baterisë\" nuk është i disponueshëm gjatë karikimit"</string>
<string name="battery_detail_switch_title" msgid="6285872470260795421">"Kursyesi i baterisë"</string>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"Pakëson veprimtarinë dhe të dhënat në sfond"</string>
+ <string name="keyboard_key_button_template" msgid="6230056639734377300">"Butoni <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="keyboard_key_home" msgid="2243500072071305073">"Kreu"</string>
+ <string name="keyboard_key_back" msgid="2337450286042721351">"Prapa"</string>
+ <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"Lart"</string>
+ <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"Poshtë"</string>
+ <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"Majtas"</string>
+ <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"Djathtas"</string>
+ <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"Qendror"</string>
+ <string name="keyboard_key_tab" msgid="3871485650463164476">"Skedë"</string>
+ <string name="keyboard_key_space" msgid="2499861316311153293">"Hapësirë"</string>
+ <string name="keyboard_key_enter" msgid="5739632123216118137">"Enter"</string>
+ <string name="keyboard_key_backspace" msgid="1559580097512385854">"Kthim prapa"</string>
+ <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"Luaj/pauzë"</string>
+ <string name="keyboard_key_media_stop" msgid="2859963958595908962">"Ndalo"</string>
+ <string name="keyboard_key_media_next" msgid="1894394911630345607">"Përpara"</string>
+ <string name="keyboard_key_media_previous" msgid="4256072387192967261">"Prapa"</string>
+ <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"Rikthe me shpejtësi"</string>
+ <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"Përparo me shpejtësi"</string>
+ <string name="keyboard_key_page_up" msgid="5654098530106845603">"Faqja lart"</string>
+ <string name="keyboard_key_page_down" msgid="8720502083731906136">"Faqja poshtë"</string>
+ <string name="keyboard_key_forward_del" msgid="1391451334716490176">"Fshi"</string>
+ <string name="keyboard_key_move_home" msgid="2765693292069487486">"Kreu"</string>
+ <string name="keyboard_key_move_end" msgid="5901174332047975247">"Fundi"</string>
+ <string name="keyboard_key_insert" msgid="8530501581636082614">"Fut"</string>
+ <string name="keyboard_key_num_lock" msgid="5052537581246772117">"Kyçja e numrave"</string>
+ <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"Tastiera numerike <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"Sistemi"</string>
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Kreu"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Të fundit"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Prapa"</string>
+ <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Njoftimet"</string>
+ <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"Shkurtoret e tastierës"</string>
+ <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"Ndërro metodën e hyrjes"</string>
+ <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"Aplikacionet"</string>
+ <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"Asistenti"</string>
+ <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"Shfletuesi"</string>
+ <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"Kontaktet"</string>
+ <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"Mail-i"</string>
+ <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"Mesazh i çastit"</string>
+ <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"Muzikë"</string>
+ <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+ <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"Kalendari"</string>
<string name="tuner_full_zen_title" msgid="4540823317772234308">"Shfaq me kontrollet e volumit"</string>
<string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Mos shqetëso"</string>
<string name="volume_dnd_silent" msgid="4363882330723050727">"Shkurtorja e butonave të volumit"</string>
@@ -559,4 +596,14 @@
<string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Lëviz lart"</string>
<string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Lëviz majtas"</string>
<string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Lëviz djathtas"</string>
+ <string name="forced_resizable_info_text" msgid="7591061837558867999">"Aplikacioni mund të mos punojë me funksionin me shumë dritare."</string>
+ <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"Pozicioni <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>. Trokit dy herë për ta redaktuar."</string>
+ <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. Trokit dy herë për ta shtuar."</string>
+ <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"Pozicioni <xliff:g id="POSITION">%1$d</xliff:g>. Trokit dy herë për ta zgjedhur."</string>
+ <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"Zhvendose <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"Hiqe <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="TILE_NAME">%1$s</xliff:g> është shtuar te pozicioni <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+ <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"<xliff:g id="TILE_NAME">%1$s</xliff:g> u hoq"</string>
+ <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="TILE_NAME">%1$s</xliff:g> u zhvendos te pozicioni <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+ <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Redaktori i cilësimeve të shpejta."</string>
</resources>
diff --git a/packages/SystemUI/res/values-sq-rAL/strings_tv.xml b/packages/SystemUI/res/values-sq-rAL/strings_tv.xml
index bcb53fc..672a119 100644
--- a/packages/SystemUI/res/values-sq-rAL/strings_tv.xml
+++ b/packages/SystemUI/res/values-sq-rAL/strings_tv.xml
@@ -26,6 +26,5 @@
<string name="pip_hold_home" msgid="340086535668778109">"Mbaj shtypur "<b>"HOME"</b>" për të kontrolluar PIP"</string>
<string name="pip_onboarding_description" msgid="2882896641362814195">"Shtyp dhe mbaj shtypur butonin HOME për të kontrolluar PIP"</string>
<string name="pip_onboarding_button" msgid="3957426748484904611">"E kuptova"</string>
- <!-- no translation found for recents_tv_dismiss (3555093879593377731) -->
- <skip />
+ <string name="recents_tv_dismiss" msgid="3555093879593377731">"Hiqe"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index 5bc07fa..501a3e3 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -169,6 +169,8 @@
<string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Одбаците <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"Апликација <xliff:g id="APP">%s</xliff:g> је одбачена."</string>
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Све недавно коришћене апликације су одбачене."</string>
+ <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+ <skip />
<string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Покрећемо <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
<string name="accessibility_notification_dismissed" msgid="854211387186306927">"Обавештење је одбачено."</string>
@@ -237,8 +239,7 @@
<string name="gps_notification_found_text" msgid="4619274244146446464">"Локацију је подесио GPS"</string>
<string name="accessibility_location_active" msgid="2427290146138169014">"Има активних захтева за локацију"</string>
<string name="accessibility_clear_all" msgid="5235938559247164925">"Обриши сва обавештења."</string>
- <!-- no translation found for notification_group_overflow_indicator (1863231301642314183) -->
- <skip />
+ <string name="notification_group_overflow_indicator" msgid="1863231301642314183">"и још <xliff:g id="NUMBER">%s</xliff:g>"</string>
<string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"Подешавања обавештења"</string>
<string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"Подешавања за <xliff:g id="APP_NAME">%s</xliff:g>"</string>
<string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Екран ће се аутоматски ротирати."</string>
@@ -311,8 +312,7 @@
<string name="recents_search_bar_label" msgid="8074997400187836677">"претражи"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"Покретање апликације <xliff:g id="APP">%s</xliff:g> није успело."</string>
<string name="recents_launch_disabled_message" msgid="1624523193008871793">"Апликација <xliff:g id="APP">%s</xliff:g> је онемогућена у безбедном режиму."</string>
- <string name="recents_history_button_label" msgid="5153358867807604821">"Историја"</string>
- <string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Обриши"</string>
+ <string name="recents_stack_action_button_label" msgid="6593727103310426253">"Обриши све"</string>
<string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"Ова апликација не подржава режим са више прозора"</string>
<string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"Апликација не подржава режим са више прозора"</string>
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Подели хоризонтално"</string>
@@ -481,8 +481,7 @@
<string name="notification_importance_max" msgid="5806278962376556491">"Приказују се у врху листе обавештења, накратко се приказују на екрану и емитују звук"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Још подешавања"</string>
<string name="notification_done" msgid="5279426047273930175">"Готово"</string>
- <!-- no translation found for notification_gear_accessibility (94429150213089611) -->
- <skip />
+ <string name="notification_gear_accessibility" msgid="94429150213089611">"Контроле обавештења за апликацију <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="color_and_appearance" msgid="1254323855964993144">"Боја и изглед"</string>
<string name="night_mode" msgid="3540405868248625488">"Ноћни режим"</string>
<string name="calibrate_display" msgid="5974642573432039217">"Калибришите екран"</string>
@@ -502,10 +501,48 @@
<string name="battery_detail_charging_summary" msgid="1279095653533044008">"Уштеда батерије није доступна током пуњења"</string>
<string name="battery_detail_switch_title" msgid="6285872470260795421">"Уштеда батерије"</string>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"Смањује перформансе и позадинске податке"</string>
+ <string name="keyboard_key_button_template" msgid="6230056639734377300">"Дугме <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="keyboard_key_home" msgid="2243500072071305073">"Тастер Почетна"</string>
+ <string name="keyboard_key_back" msgid="2337450286042721351">"Тастер Назад"</string>
+ <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"Тастер са стрелицом нагоре"</string>
+ <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"Тастер са стрелицом надоле"</string>
+ <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"Тастер са стрелицом налево"</string>
+ <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"Тастер са стрелицом надесно"</string>
+ <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"Тастер са централном стрелицом"</string>
+ <string name="keyboard_key_tab" msgid="3871485650463164476">"Табулатор"</string>
+ <string name="keyboard_key_space" msgid="2499861316311153293">"Тастер за размак"</string>
+ <string name="keyboard_key_enter" msgid="5739632123216118137">"Enter"</string>
+ <string name="keyboard_key_backspace" msgid="1559580097512385854">"Тастер за брисање уназад"</string>
+ <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"Тастер за репродукцију/паузирање"</string>
+ <string name="keyboard_key_media_stop" msgid="2859963958595908962">"Тастер за заустављање"</string>
+ <string name="keyboard_key_media_next" msgid="1894394911630345607">"Тастер Следећа"</string>
+ <string name="keyboard_key_media_previous" msgid="4256072387192967261">"Тастер Претходна"</string>
+ <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"Тастер за премотавање уназад"</string>
+ <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"Тастер за премотавање унапред"</string>
+ <string name="keyboard_key_page_up" msgid="5654098530106845603">"Тастер за страницу нагоре"</string>
+ <string name="keyboard_key_page_down" msgid="8720502083731906136">"Тастер за страницу надоле"</string>
+ <string name="keyboard_key_forward_del" msgid="1391451334716490176">"Тастер за брисање"</string>
+ <string name="keyboard_key_move_home" msgid="2765693292069487486">"Тастер Почетна"</string>
+ <string name="keyboard_key_move_end" msgid="5901174332047975247">"Тастер за крај"</string>
+ <string name="keyboard_key_insert" msgid="8530501581636082614">"Тастер за уметање"</string>
+ <string name="keyboard_key_num_lock" msgid="5052537581246772117">"Num Lock"</string>
+ <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"Тастер <xliff:g id="NAME">%1$s</xliff:g> на нумеричкој тастатури"</string>
<string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"Систем"</string>
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Почетни"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Недавни садржај"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Назад"</string>
+ <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Обавештења"</string>
+ <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"Тастерске пречице"</string>
+ <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"Промени метод уноса"</string>
+ <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"Апликације"</string>
+ <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"Апликација за помоћ"</string>
+ <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"Прегледач"</string>
+ <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"Контакти"</string>
+ <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"Имејл"</string>
+ <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"Размена тренутних порука"</string>
+ <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"Музика"</string>
+ <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+ <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"Календар"</string>
<string name="tuner_full_zen_title" msgid="4540823317772234308">"Прикажи са контролама јачине звука"</string>
<string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Не узнемиравај"</string>
<string name="volume_dnd_silent" msgid="4363882330723050727">"Пречица за дугмад за јачину звука"</string>
@@ -560,4 +597,14 @@
<string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Помери нагоре"</string>
<string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Помери улево"</string>
<string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Помери удесно"</string>
+ <string name="forced_resizable_info_text" msgid="7591061837558867999">"Апликација можда неће функционисати са више прозора"</string>
+ <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"<xliff:g id="POSITION">%1$d</xliff:g>. позиција, <xliff:g id="TILE_NAME">%2$s</xliff:g>. Двапут додирните да бисте изменили."</string>
+ <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. Двапут додирните да бисте додали."</string>
+ <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"<xliff:g id="POSITION">%1$d</xliff:g>. позиција. Двапут додирните да бисте изабрали."</string>
+ <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"Премести плочицу <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"Уклони плочицу <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"Плочица <xliff:g id="TILE_NAME">%1$s</xliff:g> је додата на <xliff:g id="POSITION">%2$d</xliff:g>. позицију"</string>
+ <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"Плочица <xliff:g id="TILE_NAME">%1$s</xliff:g> је уклоњена"</string>
+ <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"Плочица <xliff:g id="TILE_NAME">%1$s</xliff:g> је премештена на <xliff:g id="POSITION">%2$d</xliff:g>. позицију"</string>
+ <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Уређивач за Брза подешавања."</string>
</resources>
diff --git a/packages/SystemUI/res/values-sr/strings_tv.xml b/packages/SystemUI/res/values-sr/strings_tv.xml
index a92374f..d822e4e 100644
--- a/packages/SystemUI/res/values-sr/strings_tv.xml
+++ b/packages/SystemUI/res/values-sr/strings_tv.xml
@@ -26,6 +26,5 @@
<string name="pip_hold_home" msgid="340086535668778109"><b>"ПОЧЕТНИ ЕКРАН"</b>" конт. PIP"</string>
<string name="pip_onboarding_description" msgid="2882896641362814195">"Притисните и задржите дугме ПОЧЕТНИ ЕКРАН да бисте контролисали PIP"</string>
<string name="pip_onboarding_button" msgid="3957426748484904611">"Важи"</string>
- <!-- no translation found for recents_tv_dismiss (3555093879593377731) -->
- <skip />
+ <string name="recents_tv_dismiss" msgid="3555093879593377731">"Одбаци"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index 7e40ce0..959128e 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -168,6 +168,8 @@
<string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Ta bort <xliff:g id="APP">%s</xliff:g> från listan."</string>
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> togs bort permanent."</string>
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Alla appar har tagits bort från listan Senaste."</string>
+ <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+ <skip />
<string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Startar <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
<string name="accessibility_notification_dismissed" msgid="854211387186306927">"Meddelandet ignorerades."</string>
@@ -236,8 +238,7 @@
<string name="gps_notification_found_text" msgid="4619274244146446464">"Platsen har identifierats av GPS"</string>
<string name="accessibility_location_active" msgid="2427290146138169014">"Det finns aktiva platsbegäranden"</string>
<string name="accessibility_clear_all" msgid="5235938559247164925">"Ta bort alla meddelanden."</string>
- <!-- no translation found for notification_group_overflow_indicator (1863231301642314183) -->
- <skip />
+ <string name="notification_group_overflow_indicator" msgid="1863231301642314183">"<xliff:g id="NUMBER">%s</xliff:g> till"</string>
<string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"Aviseringsinställningar"</string>
<string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"Inställningar för <xliff:g id="APP_NAME">%s</xliff:g>"</string>
<string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Skärmen roteras automatiskt."</string>
@@ -310,8 +311,7 @@
<string name="recents_search_bar_label" msgid="8074997400187836677">"sök"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"Det gick inte att starta appen <xliff:g id="APP">%s</xliff:g>."</string>
<string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g> är inaktiverad i säkert läge."</string>
- <string name="recents_history_button_label" msgid="5153358867807604821">"Historik"</string>
- <string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Rensa"</string>
+ <string name="recents_stack_action_button_label" msgid="6593727103310426253">"Rensa alla"</string>
<string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"Den här appen har inte stöd för flera fönster"</string>
<string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"Appen har inte stöd för flera fönster"</string>
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Dela horisontellt"</string>
@@ -480,8 +480,7 @@
<string name="notification_importance_max" msgid="5806278962376556491">"Visa högst upp i aviseringslistan och med snabbtitt på skärmen samt tillåt ljud"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Fler inställningar"</string>
<string name="notification_done" msgid="5279426047273930175">"Klar"</string>
- <!-- no translation found for notification_gear_accessibility (94429150213089611) -->
- <skip />
+ <string name="notification_gear_accessibility" msgid="94429150213089611">"Inställningar för <xliff:g id="APP_NAME">%1$s</xliff:g>-aviseringar"</string>
<string name="color_and_appearance" msgid="1254323855964993144">"Färg och utseende"</string>
<string name="night_mode" msgid="3540405868248625488">"Nattläge"</string>
<string name="calibrate_display" msgid="5974642573432039217">"Kalibrera skärmen"</string>
@@ -501,10 +500,48 @@
<string name="battery_detail_charging_summary" msgid="1279095653533044008">"Batterisparläget är inte tillgängligt vid laddning"</string>
<string name="battery_detail_switch_title" msgid="6285872470260795421">"Batterisparläge"</string>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"Minskar prestanda och bakgrundsdata"</string>
+ <string name="keyboard_key_button_template" msgid="6230056639734377300">"Knappen <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="keyboard_key_home" msgid="2243500072071305073">"Start"</string>
+ <string name="keyboard_key_back" msgid="2337450286042721351">"Tillbaka"</string>
+ <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"Upp"</string>
+ <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"Ned"</string>
+ <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"Vänster"</string>
+ <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"Höger"</string>
+ <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"Centrera"</string>
+ <string name="keyboard_key_tab" msgid="3871485650463164476">"Flik"</string>
+ <string name="keyboard_key_space" msgid="2499861316311153293">"Blanksteg"</string>
+ <string name="keyboard_key_enter" msgid="5739632123216118137">"Retur"</string>
+ <string name="keyboard_key_backspace" msgid="1559580097512385854">"Backsteg"</string>
+ <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"Spela upp/Pausa"</string>
+ <string name="keyboard_key_media_stop" msgid="2859963958595908962">"Avsluta"</string>
+ <string name="keyboard_key_media_next" msgid="1894394911630345607">"Nästa"</string>
+ <string name="keyboard_key_media_previous" msgid="4256072387192967261">"Föregående"</string>
+ <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"Spola tillbaka"</string>
+ <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"Snabbspola framåt"</string>
+ <string name="keyboard_key_page_up" msgid="5654098530106845603">"Sida upp"</string>
+ <string name="keyboard_key_page_down" msgid="8720502083731906136">"Sida ned"</string>
+ <string name="keyboard_key_forward_del" msgid="1391451334716490176">"Radera"</string>
+ <string name="keyboard_key_move_home" msgid="2765693292069487486">"Start"</string>
+ <string name="keyboard_key_move_end" msgid="5901174332047975247">"Slut"</string>
+ <string name="keyboard_key_insert" msgid="8530501581636082614">"Infoga"</string>
+ <string name="keyboard_key_num_lock" msgid="5052537581246772117">"Num Lock"</string>
+ <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"Numeriskt tangentbord <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"System"</string>
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Startsida"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Senaste"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Tillbaka"</string>
+ <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Aviseringar"</string>
+ <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"Kortkommandon"</string>
+ <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"Byt inmatningsmetod"</string>
+ <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"Appar"</string>
+ <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"Hjälp"</string>
+ <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"Webbläsare"</string>
+ <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"Kontakter"</string>
+ <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"E-post"</string>
+ <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"Snabbmeddelanden"</string>
+ <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"Musik"</string>
+ <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+ <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"Kalender"</string>
<string name="tuner_full_zen_title" msgid="4540823317772234308">"Visa med volymkontroller"</string>
<string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Stör ej"</string>
<string name="volume_dnd_silent" msgid="4363882330723050727">"Genväg till volymknappar"</string>
@@ -559,4 +596,14 @@
<string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Flytta uppåt"</string>
<string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Flytta åt vänster"</string>
<string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Flytta åt höger"</string>
+ <string name="forced_resizable_info_text" msgid="7591061837558867999">"Appen fungerar eventuellt inte i flerfönsterläge"</string>
+ <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"Position <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>. Tryck snabbt två gånger om du vill redigera positionen."</string>
+ <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. Lägg till genom att trycka snabbt två gånger."</string>
+ <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"Position <xliff:g id="POSITION">%1$d</xliff:g>. Välj den genom att trycka snabbt två gånger."</string>
+ <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"Flytta <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"Ta bort <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="TILE_NAME">%1$s</xliff:g> har lagts till på position <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+ <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"<xliff:g id="TILE_NAME">%1$s</xliff:g> har tagits bort"</string>
+ <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="TILE_NAME">%1$s</xliff:g> har flyttats till position <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+ <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Redigerare för snabbinställningar."</string>
</resources>
diff --git a/packages/SystemUI/res/values-sv/strings_tv.xml b/packages/SystemUI/res/values-sv/strings_tv.xml
index 790ef76..0c0afc3 100644
--- a/packages/SystemUI/res/values-sv/strings_tv.xml
+++ b/packages/SystemUI/res/values-sv/strings_tv.xml
@@ -26,6 +26,5 @@
<string name="pip_hold_home" msgid="340086535668778109">"Styr PIP med "<b>"startknappen"</b></string>
<string name="pip_onboarding_description" msgid="2882896641362814195">"Styr bild-i-bild genom att hålla ned startsideknappen"</string>
<string name="pip_onboarding_button" msgid="3957426748484904611">"OK"</string>
- <!-- no translation found for recents_tv_dismiss (3555093879593377731) -->
- <skip />
+ <string name="recents_tv_dismiss" msgid="3555093879593377731">"Ignorera"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index aa9ed8a..4b936c9 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -168,6 +168,8 @@
<string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Ondoa <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> imeondolewa."</string>
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Programu za hivi majuzi zimeondolewa."</string>
+ <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+ <skip />
<string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Inaanzisha <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
<string name="accessibility_notification_dismissed" msgid="854211387186306927">"Arifa imetupwa."</string>
@@ -236,8 +238,7 @@
<string name="gps_notification_found_text" msgid="4619274244146446464">"Mahali pamewekwa na GPS"</string>
<string name="accessibility_location_active" msgid="2427290146138169014">"Maombi ya eneo yanatumika"</string>
<string name="accessibility_clear_all" msgid="5235938559247164925">"Futa arifa zote."</string>
- <!-- no translation found for notification_group_overflow_indicator (1863231301642314183) -->
- <skip />
+ <string name="notification_group_overflow_indicator" msgid="1863231301642314183">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string>
<string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"Mipangilio ya arifa"</string>
<string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"Mipangilio ya <xliff:g id="APP_NAME">%s</xliff:g>"</string>
<string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Skrini itazunguka kiotomatiki."</string>
@@ -310,8 +311,7 @@
<string name="recents_search_bar_label" msgid="8074997400187836677">"tafuta"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"Haikuweza kuanzisha <xliff:g id="APP">%s</xliff:g>."</string>
<string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g> imezimwa katika hali salama."</string>
- <string name="recents_history_button_label" msgid="5153358867807604821">"Historia"</string>
- <string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Futa"</string>
+ <string name="recents_stack_action_button_label" msgid="6593727103310426253">"Futa zote"</string>
<string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"Programu hii haitumiki katika hali ya madirisha mengi"</string>
<string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"Programu haitumiki katika hali ya madirisha mengi"</string>
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Gawanya Mlalo"</string>
@@ -480,8 +480,7 @@
<string name="notification_importance_max" msgid="5806278962376556491">"Onyesha katika sehemu ya juu ya orodha ya arifa, chungulia kwenye skrini na uruhusu sauti"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Mipangilio zaidi"</string>
<string name="notification_done" msgid="5279426047273930175">"Nimemaliza"</string>
- <!-- no translation found for notification_gear_accessibility (94429150213089611) -->
- <skip />
+ <string name="notification_gear_accessibility" msgid="94429150213089611">"Vidhibiti vya arifa za <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="color_and_appearance" msgid="1254323855964993144">"Rangi na mwonekano"</string>
<string name="night_mode" msgid="3540405868248625488">"Hali ya usiku"</string>
<string name="calibrate_display" msgid="5974642573432039217">"Rekebisha onyesho"</string>
@@ -501,10 +500,48 @@
<string name="battery_detail_charging_summary" msgid="1279095653533044008">"Kiokoa Betri hakipatikani unapochaji betri"</string>
<string name="battery_detail_switch_title" msgid="6285872470260795421">"Kiokoa Betri"</string>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"Hupunguza data ya chini chini na utendaji"</string>
+ <string name="keyboard_key_button_template" msgid="6230056639734377300">"Kitufe cha <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="keyboard_key_home" msgid="2243500072071305073">"Mwanzo"</string>
+ <string name="keyboard_key_back" msgid="2337450286042721351">"Nyuma"</string>
+ <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"Juu"</string>
+ <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"Chini"</string>
+ <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"Kushoto"</string>
+ <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"Kulia"</string>
+ <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"Katikati"</string>
+ <string name="keyboard_key_tab" msgid="3871485650463164476">"Sogeza"</string>
+ <string name="keyboard_key_space" msgid="2499861316311153293">"Nafasi"</string>
+ <string name="keyboard_key_enter" msgid="5739632123216118137">"Enter"</string>
+ <string name="keyboard_key_backspace" msgid="1559580097512385854">"Nafasinyuma"</string>
+ <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"Cheza/Sitisha"</string>
+ <string name="keyboard_key_media_stop" msgid="2859963958595908962">"Simamisha"</string>
+ <string name="keyboard_key_media_next" msgid="1894394911630345607">"Inayofuata"</string>
+ <string name="keyboard_key_media_previous" msgid="4256072387192967261">"Iliyotangulia"</string>
+ <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"Rudisha nyuma"</string>
+ <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"Sogeza mbele Haraka"</string>
+ <string name="keyboard_key_page_up" msgid="5654098530106845603">"Page Up"</string>
+ <string name="keyboard_key_page_down" msgid="8720502083731906136">"Page Down"</string>
+ <string name="keyboard_key_forward_del" msgid="1391451334716490176">"Futa"</string>
+ <string name="keyboard_key_move_home" msgid="2765693292069487486">"Mwanzo"</string>
+ <string name="keyboard_key_move_end" msgid="5901174332047975247">"Mwisho"</string>
+ <string name="keyboard_key_insert" msgid="8530501581636082614">"Ingiza"</string>
+ <string name="keyboard_key_num_lock" msgid="5052537581246772117">"Num Lock"</string>
+ <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"Numpad <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"Mfumo"</string>
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Mwanzo"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Zilizotumika majuzi"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Nyuma"</string>
+ <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Arifa"</string>
+ <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"Mikato ya Kibodi"</string>
+ <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"Badilisha mbinu ya kuingiza data"</string>
+ <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"Programu"</string>
+ <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"Programu ya maagizo ya sauti"</string>
+ <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"Kivinjari"</string>
+ <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"Anwani"</string>
+ <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"Barua pepe"</string>
+ <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"Ujumbe wa papo kwa papo"</string>
+ <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"Muziki"</string>
+ <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+ <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"Kalenda"</string>
<string name="tuner_full_zen_title" msgid="4540823317772234308">"Onyesha katika vidhibiti vya sauti"</string>
<string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Usinisumbue"</string>
<string name="volume_dnd_silent" msgid="4363882330723050727">"Njia ya mkato ya vitufe vya sauti"</string>
@@ -559,4 +596,14 @@
<string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Sogeza juu"</string>
<string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Sogeza kushoto"</string>
<string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Sogeza kulia"</string>
+ <string name="forced_resizable_info_text" msgid="7591061837558867999">"Huenda programu isifanye kazi kwenye madirisha mengi"</string>
+ <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"Nafasi ya <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>. Gonga mara mbili ili ubadilishe."</string>
+ <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. Gonga mara mbili ili uongeze."</string>
+ <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"Nafasi ya <xliff:g id="POSITION">%1$d</xliff:g>. Gonga mara mbili ili uchague."</string>
+ <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"Hamisha <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"Ondoa <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="TILE_NAME">%1$s</xliff:g> imeongezwa kwenye nafasi ya <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+ <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"<xliff:g id="TILE_NAME">%1$s</xliff:g> imeondolewa"</string>
+ <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="TILE_NAME">%1$s</xliff:g> imehamishiwa kwenye nafasi ya <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+ <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Kihariri cha Mipangilio ya haraka."</string>
</resources>
diff --git a/packages/SystemUI/res/values-sw/strings_tv.xml b/packages/SystemUI/res/values-sw/strings_tv.xml
index bd29705..4875f73 100644
--- a/packages/SystemUI/res/values-sw/strings_tv.xml
+++ b/packages/SystemUI/res/values-sw/strings_tv.xml
@@ -26,6 +26,5 @@
<string name="pip_hold_home" msgid="340086535668778109">"Shikilia kitufe cha "<b>"HOME"</b>" ili udhibiti PIP"</string>
<string name="pip_onboarding_description" msgid="2882896641362814195">"Bonyeza na ushikilie kitufe cha HOME ili kudhibiti PIP"</string>
<string name="pip_onboarding_button" msgid="3957426748484904611">"Nimeelewa"</string>
- <!-- no translation found for recents_tv_dismiss (3555093879593377731) -->
- <skip />
+ <string name="recents_tv_dismiss" msgid="3555093879593377731">"Ondoa"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ta-rIN/strings.xml b/packages/SystemUI/res/values-ta-rIN/strings.xml
index 3eb7565..5489be9 100644
--- a/packages/SystemUI/res/values-ta-rIN/strings.xml
+++ b/packages/SystemUI/res/values-ta-rIN/strings.xml
@@ -168,6 +168,8 @@
<string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"<xliff:g id="APP">%s</xliff:g> ஐ நிராகரி."</string>
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> விலக்கப்பட்டது."</string>
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"எல்லா சமீபத்திய பயன்பாடுகளும் விலக்கப்பட்டன."</string>
+ <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+ <skip />
<string name="accessibility_recents_item_launched" msgid="7616039892382525203">"<xliff:g id="APP">%s</xliff:g> ஐத் தொடங்குகிறது."</string>
<string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
<string name="accessibility_notification_dismissed" msgid="854211387186306927">"அறிவிப்பு நிராகரிக்கப்பட்டது."</string>
@@ -236,8 +238,7 @@
<string name="gps_notification_found_text" msgid="4619274244146446464">"GPS அமைத்த இருப்பிடம்"</string>
<string name="accessibility_location_active" msgid="2427290146138169014">"இருப்பிடக் கோரிக்கைகள் இயக்கப்பட்டன"</string>
<string name="accessibility_clear_all" msgid="5235938559247164925">"எல்லா அறிவிப்புகளையும் அழி."</string>
- <!-- no translation found for notification_group_overflow_indicator (1863231301642314183) -->
- <skip />
+ <string name="notification_group_overflow_indicator" msgid="1863231301642314183">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string>
<string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"அறிவிப்பு அமைப்புகள்"</string>
<string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"<xliff:g id="APP_NAME">%s</xliff:g> அமைப்புகள்"</string>
<string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"திரை தானாகச் சுழலும்."</string>
@@ -310,8 +311,7 @@
<string name="recents_search_bar_label" msgid="8074997400187836677">"தேடு"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g>ஐத் தொடங்க முடியவில்லை."</string>
<string name="recents_launch_disabled_message" msgid="1624523193008871793">"பாதுகாப்புப் பயன்முறையில் <xliff:g id="APP">%s</xliff:g> முடக்கப்பட்டது."</string>
- <string name="recents_history_button_label" msgid="5153358867807604821">"வரலாறு"</string>
- <string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"அழி"</string>
+ <string name="recents_stack_action_button_label" msgid="6593727103310426253">"அனைத்தையும் அழி"</string>
<string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"இந்தப் பயன்பாடு பல சாளர அம்சத்தை ஆதரிக்கவில்லை"</string>
<string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"பயன்பாடு பல சாளர அம்சத்தை ஆதரிக்காது"</string>
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"கிடைமட்டமாகப் பிரி"</string>
@@ -480,8 +480,7 @@
<string name="notification_importance_max" msgid="5806278962376556491">"அறிவிப்புகள் பட்டியலின் மேற்பகுதியில், சில வினாடிகளுக்கு ஒலியுடன் திரையில் காட்டு"</string>
<string name="notification_more_settings" msgid="816306283396553571">"மேலும் அமைப்புகள்"</string>
<string name="notification_done" msgid="5279426047273930175">"முடிந்தது"</string>
- <!-- no translation found for notification_gear_accessibility (94429150213089611) -->
- <skip />
+ <string name="notification_gear_accessibility" msgid="94429150213089611">"<xliff:g id="APP_NAME">%1$s</xliff:g> அறிவிப்புக் கட்டுப்பாடுகள்"</string>
<string name="color_and_appearance" msgid="1254323855964993144">"வண்ணமும் தோற்றமும்"</string>
<string name="night_mode" msgid="3540405868248625488">"இரவுப் பயன்முறை"</string>
<string name="calibrate_display" msgid="5974642573432039217">"திரையை அளவுத்திருத்தம் செய்"</string>
@@ -501,10 +500,48 @@
<string name="battery_detail_charging_summary" msgid="1279095653533044008">"சார்ஜ் செய்யும் போது பேட்டரி சேமிப்பானைப் பயன்படுத்த முடியாது"</string>
<string name="battery_detail_switch_title" msgid="6285872470260795421">"பேட்டரி சேமிப்பான்"</string>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"செயல்திறனையும் பின்புலத்தில் தரவு செயலாக்கப்படுவதையும் குறைக்கும்"</string>
+ <string name="keyboard_key_button_template" msgid="6230056639734377300">"<xliff:g id="NAME">%1$s</xliff:g> பொத்தான்"</string>
+ <string name="keyboard_key_home" msgid="2243500072071305073">"ஹோம்"</string>
+ <string name="keyboard_key_back" msgid="2337450286042721351">"பேக்"</string>
+ <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"மேலே"</string>
+ <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"கீழே"</string>
+ <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"இடது"</string>
+ <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"வலது"</string>
+ <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"நடு"</string>
+ <string name="keyboard_key_tab" msgid="3871485650463164476">"டேப்"</string>
+ <string name="keyboard_key_space" msgid="2499861316311153293">"ஸ்பேஸ்"</string>
+ <string name="keyboard_key_enter" msgid="5739632123216118137">"என்டர்"</string>
+ <string name="keyboard_key_backspace" msgid="1559580097512385854">"பேக்ஸ்பேஸ்"</string>
+ <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"பிளே/பாஸ்"</string>
+ <string name="keyboard_key_media_stop" msgid="2859963958595908962">"ஸ்டாப்"</string>
+ <string name="keyboard_key_media_next" msgid="1894394911630345607">"நெக்ஸ்ட்"</string>
+ <string name="keyboard_key_media_previous" msgid="4256072387192967261">"ப்ரீவியஸ்"</string>
+ <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"ரீவைன்ட்"</string>
+ <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"ஃபாஸ்ட் பார்வேர்டு"</string>
+ <string name="keyboard_key_page_up" msgid="5654098530106845603">"பேஜ் அப்"</string>
+ <string name="keyboard_key_page_down" msgid="8720502083731906136">"பேஜ் டவுன்"</string>
+ <string name="keyboard_key_forward_del" msgid="1391451334716490176">"டெலிட்"</string>
+ <string name="keyboard_key_move_home" msgid="2765693292069487486">"ஹோம்"</string>
+ <string name="keyboard_key_move_end" msgid="5901174332047975247">"என்ட்"</string>
+ <string name="keyboard_key_insert" msgid="8530501581636082614">"இன்சர்ட்"</string>
+ <string name="keyboard_key_num_lock" msgid="5052537581246772117">"நம்பர் லாக்"</string>
+ <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"நம்பர் பேடு <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"முறைமை"</string>
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"முகப்பு"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"சமீபத்தியவை"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"முந்தையது"</string>
+ <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"அறிவிப்புகள்"</string>
+ <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"விசைப்பலகைக் குறுக்குவழிகள்"</string>
+ <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"உள்ளீட்டு முறையை மாற்று"</string>
+ <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"பயன்பாடுகள்"</string>
+ <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"அசிஸ்ட்"</string>
+ <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"உலாவி"</string>
+ <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"தொடர்புகள்"</string>
+ <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"மின்னஞ்சல்"</string>
+ <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"IM"</string>
+ <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"மியூசிக்"</string>
+ <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+ <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"கேலெண்டர்"</string>
<string name="tuner_full_zen_title" msgid="4540823317772234308">"ஒலிக் கட்டுப்பாடுகளுடன் காட்டு"</string>
<string name="volume_and_do_not_disturb" msgid="3373784330208603030">"தொந்தரவு செய்ய வேண்டாம்"</string>
<string name="volume_dnd_silent" msgid="4363882330723050727">"ஒலியளவுப் பொத்தான்களுக்கான குறுக்குவழி"</string>
@@ -559,4 +596,14 @@
<string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"மேலே நகர்த்து"</string>
<string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"இடப்புறம் நகர்த்து"</string>
<string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"வலப்புறம் நகர்த்து"</string>
+ <string name="forced_resizable_info_text" msgid="7591061837558867999">"பல சாளர அம்சத்தில் பயன்பாடு வேலைசெய்யாமல் போகக்கூடும்"</string>
+ <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"நிலை <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>. திருத்த, இருமுறை தட்டவும்."</string>
+ <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. சேர்க்க, இருமுறை தட்டவும்."</string>
+ <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"நிலை <xliff:g id="POSITION">%1$d</xliff:g>. தேர்ந்தெடுக்க, இருமுறை தட்டவும்."</string>
+ <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"<xliff:g id="TILE_NAME">%1$s</xliff:g>ஐ நகர்த்தவும்"</string>
+ <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"<xliff:g id="TILE_NAME">%1$s</xliff:g>ஐ அகற்றவும்"</string>
+ <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="TILE_NAME">%1$s</xliff:g> நிலை <xliff:g id="POSITION">%2$d</xliff:g> இல் சேர்க்கப்பட்டது"</string>
+ <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"<xliff:g id="TILE_NAME">%1$s</xliff:g> அகற்றப்பட்டது"</string>
+ <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="TILE_NAME">%1$s</xliff:g> நிலை <xliff:g id="POSITION">%2$d</xliff:g>க்கு நகர்த்தப்பட்டது"</string>
+ <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"விரைவு அமைப்புகள் திருத்தி."</string>
</resources>
diff --git a/packages/SystemUI/res/values-ta-rIN/strings_tv.xml b/packages/SystemUI/res/values-ta-rIN/strings_tv.xml
index e75d86a..7412e27 100644
--- a/packages/SystemUI/res/values-ta-rIN/strings_tv.xml
+++ b/packages/SystemUI/res/values-ta-rIN/strings_tv.xml
@@ -26,6 +26,5 @@
<string name="pip_hold_home" msgid="340086535668778109">"PIPஐக் கட்டுப்படுத்த, "<b>"முகப்பைப்"</b>" பிடித்திருக்கவும்"</string>
<string name="pip_onboarding_description" msgid="2882896641362814195">"PIPஐக் கட்டுப்படுத்த, முகப்புப் பொத்தானை அழுத்திப் பிடிக்கவும்"</string>
<string name="pip_onboarding_button" msgid="3957426748484904611">"சரி"</string>
- <!-- no translation found for recents_tv_dismiss (3555093879593377731) -->
- <skip />
+ <string name="recents_tv_dismiss" msgid="3555093879593377731">"நிராகரி"</string>
</resources>
diff --git a/packages/SystemUI/res/values-te-rIN/strings.xml b/packages/SystemUI/res/values-te-rIN/strings.xml
index 4a6e2d7..3a72809 100644
--- a/packages/SystemUI/res/values-te-rIN/strings.xml
+++ b/packages/SystemUI/res/values-te-rIN/strings.xml
@@ -168,6 +168,8 @@
<string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"<xliff:g id="APP">%s</xliff:g>ని తీసివేయండి."</string>
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> తీసివేయబడింది."</string>
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"అన్ని ఇటీవలి అనువర్తనాలు తీసివేయబడ్డాయి."</string>
+ <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+ <skip />
<string name="accessibility_recents_item_launched" msgid="7616039892382525203">"<xliff:g id="APP">%s</xliff:g>ని ప్రారంభిస్తోంది."</string>
<string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
<string name="accessibility_notification_dismissed" msgid="854211387186306927">"నోటిఫికేషన్ తీసివేయబడింది."</string>
@@ -309,8 +311,7 @@
<string name="recents_search_bar_label" msgid="8074997400187836677">"శోధించు"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g>ని ప్రారంభించడం సాధ్యపడలేదు."</string>
<string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g> సురక్షిత-మోడ్లో నిలిపివేయబడింది."</string>
- <string name="recents_history_button_label" msgid="5153358867807604821">"చరిత్ర"</string>
- <string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"తీసివేయి"</string>
+ <string name="recents_stack_action_button_label" msgid="6593727103310426253">"అన్నీ తీసివేయి"</string>
<string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"ఈ అనువర్తనం బహుళ విండోలకు మద్దతు ఇవ్వదు"</string>
<string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"అనువర్తనం బహుళ విండోలకు మద్దతు ఇవ్వదు"</string>
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"సమతలంగా విభజించు"</string>
@@ -499,10 +500,48 @@
<string name="battery_detail_charging_summary" msgid="1279095653533044008">"ఛార్జ్ అవుతున్న సమయంలో బ్యాటరీ సేవర్ అందుబాటులో ఉండదు"</string>
<string name="battery_detail_switch_title" msgid="6285872470260795421">"బ్యాటరీ సేవర్"</string>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"పనితీరుని మరియు నేపథ్య డేటాను తగ్గిస్తుంది"</string>
+ <string name="keyboard_key_button_template" msgid="6230056639734377300">"బటన్ <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="keyboard_key_home" msgid="2243500072071305073">"Home"</string>
+ <string name="keyboard_key_back" msgid="2337450286042721351">"వెనుకకు"</string>
+ <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"పైకి"</string>
+ <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"కిందికి"</string>
+ <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"ఎడమ"</string>
+ <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"కుడి"</string>
+ <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"మధ్య"</string>
+ <string name="keyboard_key_tab" msgid="3871485650463164476">"Tab"</string>
+ <string name="keyboard_key_space" msgid="2499861316311153293">"అంతరం"</string>
+ <string name="keyboard_key_enter" msgid="5739632123216118137">"Enter"</string>
+ <string name="keyboard_key_backspace" msgid="1559580097512385854">"Backspace"</string>
+ <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"ప్లే చేయి/పాజ్ చేయి"</string>
+ <string name="keyboard_key_media_stop" msgid="2859963958595908962">"ఆపివేయి"</string>
+ <string name="keyboard_key_media_next" msgid="1894394911630345607">"తదుపరి"</string>
+ <string name="keyboard_key_media_previous" msgid="4256072387192967261">"మునుపటి"</string>
+ <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"రివైండ్ చేయి"</string>
+ <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"వేగంగా ఫార్వార్డ్ చేయి"</string>
+ <string name="keyboard_key_page_up" msgid="5654098530106845603">"Page Up"</string>
+ <string name="keyboard_key_page_down" msgid="8720502083731906136">"Page Down"</string>
+ <string name="keyboard_key_forward_del" msgid="1391451334716490176">"Delete"</string>
+ <string name="keyboard_key_move_home" msgid="2765693292069487486">"Home"</string>
+ <string name="keyboard_key_move_end" msgid="5901174332047975247">"End"</string>
+ <string name="keyboard_key_insert" msgid="8530501581636082614">"Insert"</string>
+ <string name="keyboard_key_num_lock" msgid="5052537581246772117">"Num Lock"</string>
+ <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"నంబర్ ప్యాడ్ <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"సిస్టమ్"</string>
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"హోమ్"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"ఇటీవలివి"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"వెనుకకు"</string>
+ <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"నోటిఫికేషన్లు"</string>
+ <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"కీబోర్డ్ సత్వరమార్గాలు"</string>
+ <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"ఇన్పుట్ పద్ధతిని మార్చండి"</string>
+ <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"అనువర్తనాలు"</string>
+ <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"సహాయకం"</string>
+ <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"బ్రౌజర్"</string>
+ <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"పరిచయాలు"</string>
+ <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"ఇమెయిల్"</string>
+ <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"IM"</string>
+ <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"సంగీతం"</string>
+ <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+ <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"క్యాలెండర్"</string>
<string name="tuner_full_zen_title" msgid="4540823317772234308">"వాల్యూమ్ నియంత్రణలతో చూపు"</string>
<string name="volume_and_do_not_disturb" msgid="3373784330208603030">"అంతరాయం కలిగించవద్దు"</string>
<string name="volume_dnd_silent" msgid="4363882330723050727">"వాల్యూమ్ బటన్ల సత్వరమార్గం"</string>
@@ -557,4 +596,14 @@
<string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"పైకి తరలించు"</string>
<string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"ఎడమవైపుకు తరలించు"</string>
<string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"కుడివైపుకు తరలించు"</string>
+ <string name="forced_resizable_info_text" msgid="7591061837558867999">"అనువర్తనం బహుళ విండోల రూపంలో పని చేయకపోవచ్చు"</string>
+ <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"స్థానం <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>. సవరించడానికి రెండుసార్లు నొక్కండి."</string>
+ <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. జోడించడానికి రెండుసార్లు నొక్కండి."</string>
+ <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"స్థానం <xliff:g id="POSITION">%1$d</xliff:g>. ఎంచుకోవడానికి రెండుసార్లు నొక్కండి."</string>
+ <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"<xliff:g id="TILE_NAME">%1$s</xliff:g>ని తరలిస్తుంది"</string>
+ <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"<xliff:g id="TILE_NAME">%1$s</xliff:g>ని తీసివేస్తుంది"</string>
+ <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="TILE_NAME">%1$s</xliff:g> <xliff:g id="POSITION">%2$d</xliff:g>వ స్థానానికి జోడించబడింది"</string>
+ <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"<xliff:g id="TILE_NAME">%1$s</xliff:g> తీసివేయబడింది"</string>
+ <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="TILE_NAME">%1$s</xliff:g> <xliff:g id="POSITION">%2$d</xliff:g>వ స్థానానికి తరలించబడింది"</string>
+ <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"శీఘ్ర సెట్టింగ్ల ఎడిటర్."</string>
</resources>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index 33e4346..4844c84 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -168,6 +168,8 @@
<string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"ยกเลิก <xliff:g id="APP">%s</xliff:g>"</string>
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> ถูกลบไปแล้ว"</string>
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"ปิดแอปพลิเคชันล่าสุดทั้งหมดแล้ว"</string>
+ <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+ <skip />
<string name="accessibility_recents_item_launched" msgid="7616039892382525203">"กำลังเริ่มต้น <xliff:g id="APP">%s</xliff:g>"</string>
<string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
<string name="accessibility_notification_dismissed" msgid="854211387186306927">"ปิดการแจ้งเตือนแล้ว"</string>
@@ -236,8 +238,7 @@
<string name="gps_notification_found_text" msgid="4619274244146446464">"ตำแหน่งที่กำหนดโดย GPS"</string>
<string name="accessibility_location_active" msgid="2427290146138169014">"คำขอตำแหน่งที่มีการใช้งาน"</string>
<string name="accessibility_clear_all" msgid="5235938559247164925">"ล้างการแจ้งเตือนทั้งหมด"</string>
- <!-- no translation found for notification_group_overflow_indicator (1863231301642314183) -->
- <skip />
+ <string name="notification_group_overflow_indicator" msgid="1863231301642314183">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string>
<string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"การตั้งค่าการแจ้งเตือน"</string>
<string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"การตั้งค่า <xliff:g id="APP_NAME">%s</xliff:g>"</string>
<string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"หน้าจอจะหมุนโดยอัตโนมัติ"</string>
@@ -310,8 +311,7 @@
<string name="recents_search_bar_label" msgid="8074997400187836677">"ค้นหา"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"ไม่สามารถเริ่มใช้ <xliff:g id="APP">%s</xliff:g>"</string>
<string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g> ปิดใช้ในโหมดปลอดภัย"</string>
- <string name="recents_history_button_label" msgid="5153358867807604821">"ประวัติ"</string>
- <string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"ล้าง"</string>
+ <string name="recents_stack_action_button_label" msgid="6593727103310426253">"ล้างทั้งหมด"</string>
<string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"แอปนี้ไม่สนับสนุนหลายหน้าต่าง"</string>
<string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"แอปไม่สนับสนุนหลายหน้าต่าง"</string>
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"แยกในแนวนอน"</string>
@@ -480,8 +480,7 @@
<string name="notification_importance_max" msgid="5806278962376556491">"แสดงที่ด้านบนของรายการการแจ้งเตือน แสดงบนหน้าจอและให้ส่งเสียงได้"</string>
<string name="notification_more_settings" msgid="816306283396553571">"การตั้งค่าเพิ่มเติม"</string>
<string name="notification_done" msgid="5279426047273930175">"เสร็จสิ้น"</string>
- <!-- no translation found for notification_gear_accessibility (94429150213089611) -->
- <skip />
+ <string name="notification_gear_accessibility" msgid="94429150213089611">"ส่วนควบคุมการแจ้งเตือนของ <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="color_and_appearance" msgid="1254323855964993144">"สีและลักษณะที่ปรากฏ"</string>
<string name="night_mode" msgid="3540405868248625488">"โหมดกลางคืน"</string>
<string name="calibrate_display" msgid="5974642573432039217">"ปรับเทียบการแสดงผล"</string>
@@ -501,10 +500,48 @@
<string name="battery_detail_charging_summary" msgid="1279095653533044008">"ไม่สามารถใช้โหมดประหยัดแบตเตอรี่ระหว่างการชาร์จ"</string>
<string name="battery_detail_switch_title" msgid="6285872470260795421">"โหมดประหยัดแบตเตอรี่"</string>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"ลดประสิทธิภาพการทำงานและข้อมูลแบ็กกราวด์"</string>
+ <string name="keyboard_key_button_template" msgid="6230056639734377300">"ปุ่ม <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="keyboard_key_home" msgid="2243500072071305073">"Home"</string>
+ <string name="keyboard_key_back" msgid="2337450286042721351">"กลับ"</string>
+ <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"ขึ้น"</string>
+ <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"ลง"</string>
+ <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"ซ้าย"</string>
+ <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"ขวา"</string>
+ <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"กึ่งกลาง"</string>
+ <string name="keyboard_key_tab" msgid="3871485650463164476">"แท็บ"</string>
+ <string name="keyboard_key_space" msgid="2499861316311153293">"วรรค"</string>
+ <string name="keyboard_key_enter" msgid="5739632123216118137">"Enter"</string>
+ <string name="keyboard_key_backspace" msgid="1559580097512385854">"ลบถอยหลัง"</string>
+ <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"เล่น/หยุดชั่วคราว"</string>
+ <string name="keyboard_key_media_stop" msgid="2859963958595908962">"หยุด"</string>
+ <string name="keyboard_key_media_next" msgid="1894394911630345607">"ถัดไป"</string>
+ <string name="keyboard_key_media_previous" msgid="4256072387192967261">"ก่อนหน้า"</string>
+ <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"กรอกลับ"</string>
+ <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"กรอไปข้างหน้า"</string>
+ <string name="keyboard_key_page_up" msgid="5654098530106845603">"เลื่อนหน้าขึ้น"</string>
+ <string name="keyboard_key_page_down" msgid="8720502083731906136">"เลื่อนหน้าลง"</string>
+ <string name="keyboard_key_forward_del" msgid="1391451334716490176">"ลบ"</string>
+ <string name="keyboard_key_move_home" msgid="2765693292069487486">"Home"</string>
+ <string name="keyboard_key_move_end" msgid="5901174332047975247">"End"</string>
+ <string name="keyboard_key_insert" msgid="8530501581636082614">"แทรก"</string>
+ <string name="keyboard_key_num_lock" msgid="5052537581246772117">"Num Lock"</string>
+ <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"แผงตัวเลข <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"ระบบ"</string>
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"หน้าแรก"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"ล่าสุด"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"กลับ"</string>
+ <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"การแจ้งเตือน"</string>
+ <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"แป้นพิมพ์ลัด"</string>
+ <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"สลับวิธีการป้อนข้อมูล"</string>
+ <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"แอปพลิเคชัน"</string>
+ <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"การสนับสนุน"</string>
+ <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"เบราว์เซอร์"</string>
+ <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"รายชื่อติดต่อ"</string>
+ <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"อีเมล"</string>
+ <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"IM"</string>
+ <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"เพลง"</string>
+ <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+ <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"ปฏิทิน"</string>
<string name="tuner_full_zen_title" msgid="4540823317772234308">"แสดงพร้อมการควบคุมระดับเสียง"</string>
<string name="volume_and_do_not_disturb" msgid="3373784330208603030">"ห้ามรบกวน"</string>
<string name="volume_dnd_silent" msgid="4363882330723050727">"ทางลัดปุ่มปรับระดับเสียง"</string>
@@ -540,8 +577,7 @@
<string name="select_keycode" msgid="7413765103381924584">"เลือกปุ่มแป้นพิมพ์"</string>
<string name="preview" msgid="9077832302472282938">"ดูตัวอย่าง"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"ลากเพื่อเพิ่มชิ้นส่วน"</string>
- <!-- no translation found for drag_to_remove_tiles (3361212377437088062) -->
- <skip />
+ <string name="drag_to_remove_tiles" msgid="3361212377437088062">"ลากมาที่นี่เพื่อนำออก"</string>
<string name="qs_edit" msgid="2232596095725105230">"แก้ไข"</string>
<string name="tuner_time" msgid="6572217313285536011">"เวลา"</string>
<string-array name="clock_options">
@@ -560,4 +596,14 @@
<string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"เลื่อนขึ้น"</string>
<string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"เลื่อนไปทางซ้าย"</string>
<string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"เลื่อนไปทางขวา"</string>
+ <string name="forced_resizable_info_text" msgid="7591061837558867999">"แอปอาจทำงานกับหลายหน้าต่างไม่ได้"</string>
+ <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"ตำแหน่ง <xliff:g id="POSITION">%1$d</xliff:g> <xliff:g id="TILE_NAME">%2$s</xliff:g> แตะ 2 ครั้งเพื่อแก้ไข"</string>
+ <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g> แตะ 2 ครั้งเพื่อเพิ่ม"</string>
+ <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"ตำแหน่ง <xliff:g id="POSITION">%1$d</xliff:g> แตะ 2 ครั้งเพื่อเลือก"</string>
+ <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"ย้าย <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"นำ <xliff:g id="TILE_NAME">%1$s</xliff:g> ออก"</string>
+ <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"เพิ่ม <xliff:g id="TILE_NAME">%1$s</xliff:g> ลงในตำแหน่ง <xliff:g id="POSITION">%2$d</xliff:g> แล้ว"</string>
+ <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"นำ <xliff:g id="TILE_NAME">%1$s</xliff:g> ออกแล้ว"</string>
+ <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"ย้าย <xliff:g id="TILE_NAME">%1$s</xliff:g> ไปยังตำแหน่ง <xliff:g id="POSITION">%2$d</xliff:g> แล้ว"</string>
+ <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"ตัวแก้ไขการตั้งค่าด่วน"</string>
</resources>
diff --git a/packages/SystemUI/res/values-th/strings_tv.xml b/packages/SystemUI/res/values-th/strings_tv.xml
index b43078d..d7b26687 100644
--- a/packages/SystemUI/res/values-th/strings_tv.xml
+++ b/packages/SystemUI/res/values-th/strings_tv.xml
@@ -26,6 +26,5 @@
<string name="pip_hold_home" msgid="340086535668778109">"กด "<b>"HOME"</b>" ค้างไว้เพื่อควบคุม PIP"</string>
<string name="pip_onboarding_description" msgid="2882896641362814195">"กดปุ่ม HOME ค้างไว้เพื่อควบคุม PIP"</string>
<string name="pip_onboarding_button" msgid="3957426748484904611">"รับทราบ"</string>
- <!-- no translation found for recents_tv_dismiss (3555093879593377731) -->
- <skip />
+ <string name="recents_tv_dismiss" msgid="3555093879593377731">"ปิด"</string>
</resources>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index 61eaa9d..0672959 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -168,6 +168,8 @@
<string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"I-dismiss ang <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"Hindi pinansin ang <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Na-dismiss ang lahat ng kamakailang application."</string>
+ <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+ <skip />
<string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Sinisimulan ang <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
<string name="accessibility_notification_dismissed" msgid="854211387186306927">"Na-dismiss ang notification."</string>
@@ -236,8 +238,7 @@
<string name="gps_notification_found_text" msgid="4619274244146446464">"Lokasyong itinatakda ng GPS"</string>
<string name="accessibility_location_active" msgid="2427290146138169014">"Aktibo ang mga kahilingan ng lokasyon"</string>
<string name="accessibility_clear_all" msgid="5235938559247164925">"I-clear ang lahat ng notification."</string>
- <!-- no translation found for notification_group_overflow_indicator (1863231301642314183) -->
- <skip />
+ <string name="notification_group_overflow_indicator" msgid="1863231301642314183">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string>
<string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"Mga setting ng notification"</string>
<string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"Mg setting ng <xliff:g id="APP_NAME">%s</xliff:g>"</string>
<string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Awtomatikong iikot ang screen."</string>
@@ -310,8 +311,7 @@
<string name="recents_search_bar_label" msgid="8074997400187836677">"maghanap"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"Hindi masimulan <xliff:g id="APP">%s</xliff:g>."</string>
<string name="recents_launch_disabled_message" msgid="1624523193008871793">"Naka-disable ang <xliff:g id="APP">%s</xliff:g> sa safe-mode."</string>
- <string name="recents_history_button_label" msgid="5153358867807604821">"History"</string>
- <string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"I-clear"</string>
+ <string name="recents_stack_action_button_label" msgid="6593727103310426253">"I-clear lahat"</string>
<string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"Hindi sinusuportahan ng app na ito ang multi-window"</string>
<string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"Hindi sinusuportahan ng app na ito ang multi-window"</string>
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Split Horizontal"</string>
@@ -480,8 +480,7 @@
<string name="notification_importance_max" msgid="5806278962376556491">"Ipakita sa itaas ng listahan ng mga notification, palitawin sa screen at payagang tumunog"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Higit pang mga setting"</string>
<string name="notification_done" msgid="5279426047273930175">"Tapos Na"</string>
- <!-- no translation found for notification_gear_accessibility (94429150213089611) -->
- <skip />
+ <string name="notification_gear_accessibility" msgid="94429150213089611">"Mga kontrol sa notification ng <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="color_and_appearance" msgid="1254323855964993144">"Kulay at hitsura"</string>
<string name="night_mode" msgid="3540405868248625488">"Night mode"</string>
<string name="calibrate_display" msgid="5974642573432039217">"I-calibrate ang display"</string>
@@ -501,10 +500,48 @@
<string name="battery_detail_charging_summary" msgid="1279095653533044008">"Hindi available ang Pangtipid sa Baterya kapag nagcha-charge"</string>
<string name="battery_detail_switch_title" msgid="6285872470260795421">"Pangtipid sa Baterya"</string>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"Binabawasan ang pagganap at data sa background"</string>
+ <string name="keyboard_key_button_template" msgid="6230056639734377300">"Button na <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="keyboard_key_home" msgid="2243500072071305073">"Home"</string>
+ <string name="keyboard_key_back" msgid="2337450286042721351">"Back"</string>
+ <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"Up"</string>
+ <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"Down"</string>
+ <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"Left"</string>
+ <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"Right"</string>
+ <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"Center"</string>
+ <string name="keyboard_key_tab" msgid="3871485650463164476">"Tab"</string>
+ <string name="keyboard_key_space" msgid="2499861316311153293">"Space"</string>
+ <string name="keyboard_key_enter" msgid="5739632123216118137">"Enter"</string>
+ <string name="keyboard_key_backspace" msgid="1559580097512385854">"Backspace"</string>
+ <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"Play/Pause"</string>
+ <string name="keyboard_key_media_stop" msgid="2859963958595908962">"Stop"</string>
+ <string name="keyboard_key_media_next" msgid="1894394911630345607">"Next"</string>
+ <string name="keyboard_key_media_previous" msgid="4256072387192967261">"Previous"</string>
+ <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"Rewind"</string>
+ <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"Fast Forward"</string>
+ <string name="keyboard_key_page_up" msgid="5654098530106845603">"Page Up"</string>
+ <string name="keyboard_key_page_down" msgid="8720502083731906136">"Page Down"</string>
+ <string name="keyboard_key_forward_del" msgid="1391451334716490176">"Delete"</string>
+ <string name="keyboard_key_move_home" msgid="2765693292069487486">"Home"</string>
+ <string name="keyboard_key_move_end" msgid="5901174332047975247">"End"</string>
+ <string name="keyboard_key_insert" msgid="8530501581636082614">"Insert"</string>
+ <string name="keyboard_key_num_lock" msgid="5052537581246772117">"Num Lock"</string>
+ <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"Numpad <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"System"</string>
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Home"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Mga Kamakailang Ginamit"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Bumalik"</string>
+ <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Mga Notification"</string>
+ <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"Mga Keyboard Shortcut"</string>
+ <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"Magpalit ng pamamaraan ng pag-input"</string>
+ <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"Mga Application"</string>
+ <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"Tulong"</string>
+ <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"Browser"</string>
+ <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"Mga Contact"</string>
+ <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"Email"</string>
+ <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"IM"</string>
+ <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"Music"</string>
+ <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+ <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"Kalendaryo"</string>
<string name="tuner_full_zen_title" msgid="4540823317772234308">"Ipakita nang may mga kontrol ng volume"</string>
<string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Huwag istorbohin"</string>
<string name="volume_dnd_silent" msgid="4363882330723050727">"Shortcut ng mga button ng volume"</string>
@@ -559,4 +596,14 @@
<string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Ilipat pataas"</string>
<string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Ilipat pakaliwa"</string>
<string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Ilipat pakanan"</string>
+ <string name="forced_resizable_info_text" msgid="7591061837558867999">"Maaaring hindi gumana ang app sa maraming window"</string>
+ <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"Posisyon <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>. I-double tap upang i-edit."</string>
+ <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. I-double tap upang idagdag."</string>
+ <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"Posisyon <xliff:g id="POSITION">%1$d</xliff:g>. I-double tap upang piliin."</string>
+ <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"Ilipat ang <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"Alisin ang <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"Idinagdag ang <xliff:g id="TILE_NAME">%1$s</xliff:g> sa posisyon <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+ <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"Inalis ang <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"Inilipat ang <xliff:g id="TILE_NAME">%1$s</xliff:g> sa posisyon <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+ <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Editor ng Mga mabilisang setting."</string>
</resources>
diff --git a/packages/SystemUI/res/values-tl/strings_tv.xml b/packages/SystemUI/res/values-tl/strings_tv.xml
index 8d4b1b0..74fe314 100644
--- a/packages/SystemUI/res/values-tl/strings_tv.xml
+++ b/packages/SystemUI/res/values-tl/strings_tv.xml
@@ -26,6 +26,5 @@
<string name="pip_hold_home" msgid="340086535668778109">"I-hold ang "<b>"HOME"</b>" para makontrol ang PIP"</string>
<string name="pip_onboarding_description" msgid="2882896641362814195">"Pindutin nang matagal ang button ng HOME upang makontrol ang PIP"</string>
<string name="pip_onboarding_button" msgid="3957426748484904611">"OK"</string>
- <!-- no translation found for recents_tv_dismiss (3555093879593377731) -->
- <skip />
+ <string name="recents_tv_dismiss" msgid="3555093879593377731">"I-dismiss"</string>
</resources>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index d5a8b9b..58d488c 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -168,6 +168,8 @@
<string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"<xliff:g id="APP">%s</xliff:g> uygulamasını kapat."</string>
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> kaldırıldı."</string>
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Tüm son uygulamalar kapatıldı."</string>
+ <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+ <skip />
<string name="accessibility_recents_item_launched" msgid="7616039892382525203">"<xliff:g id="APP">%s</xliff:g> başlatılıyor."</string>
<string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
<string name="accessibility_notification_dismissed" msgid="854211387186306927">"Bildirim kapatıldı."</string>
@@ -236,8 +238,7 @@
<string name="gps_notification_found_text" msgid="4619274244146446464">"Konum GPS ile belirlendi"</string>
<string name="accessibility_location_active" msgid="2427290146138169014">"Konum bilgisi istekleri etkin"</string>
<string name="accessibility_clear_all" msgid="5235938559247164925">"Tüm bildirimleri temizle"</string>
- <!-- no translation found for notification_group_overflow_indicator (1863231301642314183) -->
- <skip />
+ <string name="notification_group_overflow_indicator" msgid="1863231301642314183">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string>
<string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"Bildirim ayarları"</string>
<string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"<xliff:g id="APP_NAME">%s</xliff:g> ayarları"</string>
<string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Ekran otomatik olarak dönecektir."</string>
@@ -310,8 +311,7 @@
<string name="recents_search_bar_label" msgid="8074997400187836677">"ara"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g> başlatılamadı."</string>
<string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g>, güvenli modda devre dışıdır."</string>
- <string name="recents_history_button_label" msgid="5153358867807604821">"Geçmiş"</string>
- <string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Sil"</string>
+ <string name="recents_stack_action_button_label" msgid="6593727103310426253">"Tümünü temizle"</string>
<string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"Bu uygulama, çoklu pencere kullanımını desteklemiyor"</string>
<string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"Uygulama, çoklu pencere kullanımını desteklemiyor"</string>
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Yatay Ayırma"</string>
@@ -480,8 +480,7 @@
<string name="notification_importance_max" msgid="5806278962376556491">"Bildirim listesinin üstünde göster, ekrana getir ve sesli bildirime izin ver"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Diğer ayarlar"</string>
<string name="notification_done" msgid="5279426047273930175">"Bitti"</string>
- <!-- no translation found for notification_gear_accessibility (94429150213089611) -->
- <skip />
+ <string name="notification_gear_accessibility" msgid="94429150213089611">"<xliff:g id="APP_NAME">%1$s</xliff:g> bildirim denetimleri"</string>
<string name="color_and_appearance" msgid="1254323855964993144">"Renk ve görünüm"</string>
<string name="night_mode" msgid="3540405868248625488">"Gece modu"</string>
<string name="calibrate_display" msgid="5974642573432039217">"Ekranı kalibre et"</string>
@@ -501,10 +500,48 @@
<string name="battery_detail_charging_summary" msgid="1279095653533044008">"Şarj sırasında Pil Tasarrufu özelliği kullanılamaz"</string>
<string name="battery_detail_switch_title" msgid="6285872470260795421">"Pil Tasarrufu"</string>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"Performansı ve arka plan verilerini azaltır"</string>
+ <string name="keyboard_key_button_template" msgid="6230056639734377300">"<xliff:g id="NAME">%1$s</xliff:g> düğmesi"</string>
+ <string name="keyboard_key_home" msgid="2243500072071305073">"Home"</string>
+ <string name="keyboard_key_back" msgid="2337450286042721351">"Geri"</string>
+ <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"Yukarı"</string>
+ <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"Aşağı"</string>
+ <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"Sol"</string>
+ <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"Sağ"</string>
+ <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"Orta"</string>
+ <string name="keyboard_key_tab" msgid="3871485650463164476">"Sekme"</string>
+ <string name="keyboard_key_space" msgid="2499861316311153293">"Boşluk"</string>
+ <string name="keyboard_key_enter" msgid="5739632123216118137">"Enter"</string>
+ <string name="keyboard_key_backspace" msgid="1559580097512385854">"Geri tuşu"</string>
+ <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"Oynat/Duraklat"</string>
+ <string name="keyboard_key_media_stop" msgid="2859963958595908962">"Durdur"</string>
+ <string name="keyboard_key_media_next" msgid="1894394911630345607">"Sonraki"</string>
+ <string name="keyboard_key_media_previous" msgid="4256072387192967261">"Önceki"</string>
+ <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"Geri Sar"</string>
+ <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"İleri Sar"</string>
+ <string name="keyboard_key_page_up" msgid="5654098530106845603">"Sayfa Yukarı"</string>
+ <string name="keyboard_key_page_down" msgid="8720502083731906136">"Sayfa Aşağı"</string>
+ <string name="keyboard_key_forward_del" msgid="1391451334716490176">"Delete"</string>
+ <string name="keyboard_key_move_home" msgid="2765693292069487486">"Home"</string>
+ <string name="keyboard_key_move_end" msgid="5901174332047975247">"End"</string>
+ <string name="keyboard_key_insert" msgid="8530501581636082614">"Insert"</string>
+ <string name="keyboard_key_num_lock" msgid="5052537581246772117">"Num Lock"</string>
+ <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"<xliff:g id="NAME">%1$s</xliff:g> (Sayısal Tuş Takımında)"</string>
<string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"Sistem"</string>
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Ana ekran"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Son çağrılar"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Geri"</string>
+ <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Bildirimler"</string>
+ <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"Klavye Kısayolları"</string>
+ <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"Giriş yöntemini değiştir"</string>
+ <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"Uygulamalar"</string>
+ <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"Asist"</string>
+ <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"Tarayıcı"</string>
+ <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"Kişiler"</string>
+ <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"E-posta"</string>
+ <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"IM"</string>
+ <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"Müzik"</string>
+ <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+ <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"Takvim"</string>
<string name="tuner_full_zen_title" msgid="4540823317772234308">"Ses seviyesi kontrolleriyle göster"</string>
<string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Rahatsız etmeyin"</string>
<string name="volume_dnd_silent" msgid="4363882330723050727">"Ses düğmeleri kısayolu"</string>
@@ -559,4 +596,14 @@
<string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Yukarı taşı"</string>
<string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Sola taşı"</string>
<string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Sağa taşı"</string>
+ <string name="forced_resizable_info_text" msgid="7591061837558867999">"Uygulama birden fazla pencerede çalışmayabilir"</string>
+ <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"<xliff:g id="POSITION">%1$d</xliff:g>. konum, <xliff:g id="TILE_NAME">%2$s</xliff:g>. Düzenlemek için iki kez hafifçe dokunun."</string>
+ <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. Eklemek için iki kez hafifçe dokunun."</string>
+ <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"<xliff:g id="POSITION">%1$d</xliff:g>. konum. Seçmek için iki kez hafifçe dokunun."</string>
+ <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"<xliff:g id="TILE_NAME">%1$s</xliff:g> kutusunu taşı"</string>
+ <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"<xliff:g id="TILE_NAME">%1$s</xliff:g> kutusunu kaldır"</string>
+ <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="TILE_NAME">%1$s</xliff:g> kutusu <xliff:g id="POSITION">%2$d</xliff:g>. konuma eklendi"</string>
+ <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"<xliff:g id="TILE_NAME">%1$s</xliff:g> kaldırıldı"</string>
+ <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="TILE_NAME">%1$s</xliff:g> <xliff:g id="POSITION">%2$d</xliff:g>. konumuna taşındı"</string>
+ <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Hızlı ayar düzenleyicisi."</string>
</resources>
diff --git a/packages/SystemUI/res/values-tr/strings_tv.xml b/packages/SystemUI/res/values-tr/strings_tv.xml
index a5be6a2..57da7fb 100644
--- a/packages/SystemUI/res/values-tr/strings_tv.xml
+++ b/packages/SystemUI/res/values-tr/strings_tv.xml
@@ -26,6 +26,5 @@
<string name="pip_hold_home" msgid="340086535668778109">"PIP\'yi kontrol etmek için "<b>"ANA EKRAN"</b>"\'ı basılı tutun"</string>
<string name="pip_onboarding_description" msgid="2882896641362814195">"PIP\'yi kontrol etmek için ANA EKRAN düğmesini basılı tutun"</string>
<string name="pip_onboarding_button" msgid="3957426748484904611">"Anladım"</string>
- <!-- no translation found for recents_tv_dismiss (3555093879593377731) -->
- <skip />
+ <string name="recents_tv_dismiss" msgid="3555093879593377731">"Kapat"</string>
</resources>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index 398dea1..c75891c 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -170,6 +170,8 @@
<string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Видалити додаток <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"Програму <xliff:g id="APP">%s</xliff:g> закрито."</string>
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Усі останні додатки закрито."</string>
+ <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+ <skip />
<string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Запуск додатка <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
<string name="accessibility_notification_dismissed" msgid="854211387186306927">"Сповіщення відхилено."</string>
@@ -311,8 +313,7 @@
<string name="recents_search_bar_label" msgid="8074997400187836677">"пошук"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"Не вдалося запустити <xliff:g id="APP">%s</xliff:g>."</string>
<string name="recents_launch_disabled_message" msgid="1624523193008871793">"Додаток <xliff:g id="APP">%s</xliff:g> вимкнено в безпечному режимі."</string>
- <string name="recents_history_button_label" msgid="5153358867807604821">"Історія"</string>
- <string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Очистити"</string>
+ <string name="recents_stack_action_button_label" msgid="6593727103310426253">"Очистити все"</string>
<string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"Цей додаток не підтримує багатоекранний режим"</string>
<string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"Додаток не підтримує багатоекранний режим"</string>
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Розділити горизонтально"</string>
@@ -501,10 +502,48 @@
<string name="battery_detail_charging_summary" msgid="1279095653533044008">"Режим економії заряду акумулятора недоступний під час заряджання"</string>
<string name="battery_detail_switch_title" msgid="6285872470260795421">"Режим економії заряду акумулятора"</string>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"Знижується продуктивність і обмежується обмін даними у фоновому режимі"</string>
+ <string name="keyboard_key_button_template" msgid="6230056639734377300">"Кнопка <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="keyboard_key_home" msgid="2243500072071305073">"Home"</string>
+ <string name="keyboard_key_back" msgid="2337450286042721351">"Назад"</string>
+ <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"Стрілка вгору"</string>
+ <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"Стрілка вниз"</string>
+ <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"Стрілка вліво"</string>
+ <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"Стрілка вправо"</string>
+ <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"Центр"</string>
+ <string name="keyboard_key_tab" msgid="3871485650463164476">"Tab"</string>
+ <string name="keyboard_key_space" msgid="2499861316311153293">"Пробіл"</string>
+ <string name="keyboard_key_enter" msgid="5739632123216118137">"Enter"</string>
+ <string name="keyboard_key_backspace" msgid="1559580097512385854">"Backspace"</string>
+ <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"Відтворити/призупинити"</string>
+ <string name="keyboard_key_media_stop" msgid="2859963958595908962">"Зупинити"</string>
+ <string name="keyboard_key_media_next" msgid="1894394911630345607">"Далі"</string>
+ <string name="keyboard_key_media_previous" msgid="4256072387192967261">"Назад"</string>
+ <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"Перемотати назад"</string>
+ <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"Перемотати вперед"</string>
+ <string name="keyboard_key_page_up" msgid="5654098530106845603">"Сторінка вгору"</string>
+ <string name="keyboard_key_page_down" msgid="8720502083731906136">"Сторінка вниз"</string>
+ <string name="keyboard_key_forward_del" msgid="1391451334716490176">"Delete"</string>
+ <string name="keyboard_key_move_home" msgid="2765693292069487486">"Home"</string>
+ <string name="keyboard_key_move_end" msgid="5901174332047975247">"End"</string>
+ <string name="keyboard_key_insert" msgid="8530501581636082614">"Insert"</string>
+ <string name="keyboard_key_num_lock" msgid="5052537581246772117">"Num Lock"</string>
+ <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"Numpad <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"Система"</string>
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Головний екран"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Останні"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Назад"</string>
+ <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Сповіщення"</string>
+ <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"Комбінації клавіш"</string>
+ <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"Змінити метод введення"</string>
+ <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"Додатки"</string>
+ <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"Помічник"</string>
+ <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"Веб-переглядач"</string>
+ <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"Контакти"</string>
+ <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"Електронна пошта"</string>
+ <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"Чат"</string>
+ <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"Музика"</string>
+ <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+ <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"Календар"</string>
<string name="tuner_full_zen_title" msgid="4540823317772234308">"Показувати регулятори гучності"</string>
<string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Не турбувати"</string>
<string name="volume_dnd_silent" msgid="4363882330723050727">"Кнопки гучності на корпусі"</string>
@@ -559,4 +598,14 @@
<string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Перемістити вгору"</string>
<string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Перемістити ліворуч"</string>
<string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Перемістити праворуч"</string>
+ <string name="forced_resizable_info_text" msgid="7591061837558867999">"Додаток може не працювати в багатовіконному режимі"</string>
+ <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"Позиція <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>. Двічі торкніться, щоб змінити."</string>
+ <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. Двічі торкніться, щоб додати."</string>
+ <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"Позиція <xliff:g id="POSITION">%1$d</xliff:g>. Двічі торкніться, щоб вибрати."</string>
+ <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"Перемістити <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"Видалити <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="TILE_NAME">%1$s</xliff:g> додано на позицію <xliff:g id="POSITION">%2$d</xliff:g>."</string>
+ <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"<xliff:g id="TILE_NAME">%1$s</xliff:g> видалено"</string>
+ <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="TILE_NAME">%1$s</xliff:g> переміщено на позицію <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+ <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Редактор швидких налаштувань."</string>
</resources>
diff --git a/packages/SystemUI/res/values-ur-rPK/strings.xml b/packages/SystemUI/res/values-ur-rPK/strings.xml
index 7b5013f..807a923 100644
--- a/packages/SystemUI/res/values-ur-rPK/strings.xml
+++ b/packages/SystemUI/res/values-ur-rPK/strings.xml
@@ -168,6 +168,8 @@
<string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"<xliff:g id="APP">%s</xliff:g> کو مسترد کریں۔"</string>
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> کو ہٹا دیا گیا۔"</string>
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"سبھی حالیہ ایپلیکیشنز کو برخاست کر دیا گیا۔"</string>
+ <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+ <skip />
<string name="accessibility_recents_item_launched" msgid="7616039892382525203">"<xliff:g id="APP">%s</xliff:g> شروع ہو رہی ہے۔"</string>
<string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
<string name="accessibility_notification_dismissed" msgid="854211387186306927">"اطلاع مسترد ہوگئی۔"</string>
@@ -236,8 +238,7 @@
<string name="gps_notification_found_text" msgid="4619274244146446464">"مقام متعین کیا گیا بذریعہ GPS"</string>
<string name="accessibility_location_active" msgid="2427290146138169014">"مقام کی درخواستیں فعال ہیں"</string>
<string name="accessibility_clear_all" msgid="5235938559247164925">"سبھی اطلاعات صاف کریں۔"</string>
- <!-- no translation found for notification_group_overflow_indicator (1863231301642314183) -->
- <skip />
+ <string name="notification_group_overflow_indicator" msgid="1863231301642314183">"<xliff:g id="NUMBER">%s</xliff:g> +"</string>
<string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"اطلاع کی ترتیبات"</string>
<string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"<xliff:g id="APP_NAME">%s</xliff:g> ترتیبات"</string>
<string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"اسکرین خود بخود گردش کرے گی۔"</string>
@@ -310,8 +311,7 @@
<string name="recents_search_bar_label" msgid="8074997400187836677">"تلاش کریں"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g> کو شروع نہیں کیا جا سکا۔"</string>
<string name="recents_launch_disabled_message" msgid="1624523193008871793">"محفوظ موڈ میں <xliff:g id="APP">%s</xliff:g> غیر فعال ہوتی ہے۔"</string>
- <string name="recents_history_button_label" msgid="5153358867807604821">"سرگزشت"</string>
- <string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"صاف کریں"</string>
+ <string name="recents_stack_action_button_label" msgid="6593727103310426253">"سبھی کو صاف کریں"</string>
<string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"یہ ایپ ملٹی ونڈو کی معاونت نہیں کرتی"</string>
<string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"ایپ ملٹی ونڈز کی معاونت نہیں کرتی"</string>
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"بلحاظ افقی الگ کریں"</string>
@@ -480,8 +480,7 @@
<string name="notification_importance_max" msgid="5806278962376556491">"اطلاعات کی فہرست پر سب سے اوپر دکھائیں، اسکرین پر دکھائیں اور آواز کی اجازت دیں"</string>
<string name="notification_more_settings" msgid="816306283396553571">"مزید ترتیبات"</string>
<string name="notification_done" msgid="5279426047273930175">"ہوگیا"</string>
- <!-- no translation found for notification_gear_accessibility (94429150213089611) -->
- <skip />
+ <string name="notification_gear_accessibility" msgid="94429150213089611">"<xliff:g id="APP_NAME">%1$s</xliff:g> کے نوٹیفکیشن کنٹرولز"</string>
<string name="color_and_appearance" msgid="1254323855964993144">"رنگ اور ظہور"</string>
<string name="night_mode" msgid="3540405868248625488">"رات موڈ"</string>
<string name="calibrate_display" msgid="5974642573432039217">"نشان زد ڈسپلے"</string>
@@ -501,10 +500,48 @@
<string name="battery_detail_charging_summary" msgid="1279095653533044008">"چارجنگ کے دوران بیٹری سیور دستیاب نہیں ہے"</string>
<string name="battery_detail_switch_title" msgid="6285872470260795421">"بیٹری سیور"</string>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"کارکردگی اور پس منظر کا ڈیٹا کم کر دیتا ہے"</string>
+ <string name="keyboard_key_button_template" msgid="6230056639734377300">"بٹن <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="keyboard_key_home" msgid="2243500072071305073">"Home"</string>
+ <string name="keyboard_key_back" msgid="2337450286042721351">"پیچھے"</string>
+ <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"اوپر"</string>
+ <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"نیچے"</string>
+ <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"بائیں"</string>
+ <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"دائیں"</string>
+ <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"سینٹر"</string>
+ <string name="keyboard_key_tab" msgid="3871485650463164476">"Tab"</string>
+ <string name="keyboard_key_space" msgid="2499861316311153293">"Space"</string>
+ <string name="keyboard_key_enter" msgid="5739632123216118137">"Enter"</string>
+ <string name="keyboard_key_backspace" msgid="1559580097512385854">"Backspace"</string>
+ <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"چلائیں/موقوف کریں"</string>
+ <string name="keyboard_key_media_stop" msgid="2859963958595908962">"روکیں"</string>
+ <string name="keyboard_key_media_next" msgid="1894394911630345607">"اگلا"</string>
+ <string name="keyboard_key_media_previous" msgid="4256072387192967261">"گزشتہ"</string>
+ <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"ریوائینڈ کریں"</string>
+ <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"تیزی سے فارورڈ کریں"</string>
+ <string name="keyboard_key_page_up" msgid="5654098530106845603">"Page Up"</string>
+ <string name="keyboard_key_page_down" msgid="8720502083731906136">"Page Down"</string>
+ <string name="keyboard_key_forward_del" msgid="1391451334716490176">"Delete"</string>
+ <string name="keyboard_key_move_home" msgid="2765693292069487486">"Home"</string>
+ <string name="keyboard_key_move_end" msgid="5901174332047975247">"End"</string>
+ <string name="keyboard_key_insert" msgid="8530501581636082614">"Insert"</string>
+ <string name="keyboard_key_num_lock" msgid="5052537581246772117">"Num Lock"</string>
+ <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"نمبر پیڈ <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"سسٹم"</string>
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"ہوم"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"حالیہ"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"پیچھے"</string>
+ <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"اطلاعات"</string>
+ <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"کی بورڈ شارٹ کٹس"</string>
+ <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"اندراج کا طریقہ سوئچ کریں"</string>
+ <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"ایپلیکیشنز"</string>
+ <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"اسسٹ"</string>
+ <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"براؤزر"</string>
+ <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"رابطے"</string>
+ <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"ای میل"</string>
+ <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"IM"</string>
+ <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"موسیقی"</string>
+ <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+ <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"کیلنڈر"</string>
<string name="tuner_full_zen_title" msgid="4540823317772234308">"والیوم کنٹرولز کے ساتھ دکھائیں"</string>
<string name="volume_and_do_not_disturb" msgid="3373784330208603030">"ڈسٹرب نہ کریں"</string>
<string name="volume_dnd_silent" msgid="4363882330723050727">"والیوم بٹنز کے شارٹ کٹ"</string>
@@ -559,4 +596,14 @@
<string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"اوپر منتقل کریں"</string>
<string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"بائیں منتقل کریں"</string>
<string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"دائیں منتقل کریں"</string>
+ <string name="forced_resizable_info_text" msgid="7591061837558867999">"ایپ شاید ملٹی ونڈو کے ساتھ کام نہ کرے"</string>
+ <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"پوزیشن <xliff:g id="POSITION">%1$d</xliff:g>، <xliff:g id="TILE_NAME">%2$s</xliff:g>۔ ترمیم کرنے کیلئے دو بار تھپتھپائیں۔"</string>
+ <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>۔ شامل کرنے کیلئے دو بار تھپتھپائیں۔"</string>
+ <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"پوزیشن <xliff:g id="POSITION">%1$d</xliff:g>۔ منتخب کرنے کیلئے دو بار تھپتھپائیں۔"</string>
+ <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"<xliff:g id="TILE_NAME">%1$s</xliff:g> کو منتقل کریں"</string>
+ <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"<xliff:g id="TILE_NAME">%1$s</xliff:g> ہٹائیں"</string>
+ <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="POSITION">%2$d</xliff:g> پوزیشن پر <xliff:g id="TILE_NAME">%1$s</xliff:g> شامل ہو گیا ہے"</string>
+ <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"<xliff:g id="TILE_NAME">%1$s</xliff:g> ہٹا دیا گیا"</string>
+ <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="POSITION">%2$d</xliff:g> پوزیشن پر <xliff:g id="TILE_NAME">%1$s</xliff:g> منتقل ہو گیا ہے"</string>
+ <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"فوری ترتیبات کا ایڈیٹر۔"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ur-rPK/strings_tv.xml b/packages/SystemUI/res/values-ur-rPK/strings_tv.xml
index aff14b2..78de898 100644
--- a/packages/SystemUI/res/values-ur-rPK/strings_tv.xml
+++ b/packages/SystemUI/res/values-ur-rPK/strings_tv.xml
@@ -26,6 +26,5 @@
<string name="pip_hold_home" msgid="340086535668778109">"PIP کنٹرول کرنے کیلئے "<b>"ہوم"</b>" پکڑے رکھیں"</string>
<string name="pip_onboarding_description" msgid="2882896641362814195">"PIP کنٹرول کرنے کیلئے ہوم بٹن دبائیں اور پکڑے رکھیں"</string>
<string name="pip_onboarding_button" msgid="3957426748484904611">"سمجھ آ گئی"</string>
- <!-- no translation found for recents_tv_dismiss (3555093879593377731) -->
- <skip />
+ <string name="recents_tv_dismiss" msgid="3555093879593377731">"برخاست کریں"</string>
</resources>
diff --git a/packages/SystemUI/res/values-uz-rUZ/strings.xml b/packages/SystemUI/res/values-uz-rUZ/strings.xml
index bd606c2..fe67b52 100644
--- a/packages/SystemUI/res/values-uz-rUZ/strings.xml
+++ b/packages/SystemUI/res/values-uz-rUZ/strings.xml
@@ -168,6 +168,8 @@
<string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Olib tashlash: <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> olib tashlangan."</string>
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Yaqinda ishlatilgan barcha ilovalar olib tashlandi."</string>
+ <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+ <skip />
<string name="accessibility_recents_item_launched" msgid="7616039892382525203">"<xliff:g id="APP">%s</xliff:g> ishga tushirilmoqda."</string>
<string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
<string name="accessibility_notification_dismissed" msgid="854211387186306927">"Xabarnoma e‘tiborsiz qoldirildi."</string>
@@ -236,8 +238,7 @@
<string name="gps_notification_found_text" msgid="4619274244146446464">"GPS yordamida manzilni o‘rnatish"</string>
<string name="accessibility_location_active" msgid="2427290146138169014">"Joylashuv so‘rovlari yoniq"</string>
<string name="accessibility_clear_all" msgid="5235938559247164925">"Barcha eslatmalarni tozalash."</string>
- <!-- no translation found for notification_group_overflow_indicator (1863231301642314183) -->
- <skip />
+ <string name="notification_group_overflow_indicator" msgid="1863231301642314183">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string>
<string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"Bildirishnoma sozlamalari"</string>
<string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"<xliff:g id="APP_NAME">%s</xliff:g> sozlamalari"</string>
<string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Ekran avtomatik buriladi."</string>
@@ -310,8 +311,7 @@
<string name="recents_search_bar_label" msgid="8074997400187836677">"qidirish"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"“<xliff:g id="APP">%s</xliff:g>” ilovasini ishga tushirib bo‘lmadi."</string>
<string name="recents_launch_disabled_message" msgid="1624523193008871793">"Xavfsiz rejimda <xliff:g id="APP">%s</xliff:g> ilovasi o‘chirib qo‘yildi."</string>
- <string name="recents_history_button_label" msgid="5153358867807604821">"Jurnal"</string>
- <string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Tozalash"</string>
+ <string name="recents_stack_action_button_label" msgid="6593727103310426253">"Hammasini tozalash"</string>
<string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"Bu ilova ko‘p oynali rejimni qo‘llab-quvvatlamaydi"</string>
<string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"Bu ilova ko‘p oynali rejimni qo‘llab-quvvatlamaydi"</string>
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Gorizontal yo‘nalishda bo‘lish"</string>
@@ -480,8 +480,7 @@
<string name="notification_importance_max" msgid="5806278962376556491">"Bildirishnomalar ro‘yxatining boshida va barcha oynalar ustida ovoz bilan ko‘rsatilsin"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Boshqa sozlamalar"</string>
<string name="notification_done" msgid="5279426047273930175">"Tayyor"</string>
- <!-- no translation found for notification_gear_accessibility (94429150213089611) -->
- <skip />
+ <string name="notification_gear_accessibility" msgid="94429150213089611">"<xliff:g id="APP_NAME">%1$s</xliff:g> bildirishnomalarini boshqarish"</string>
<string name="color_and_appearance" msgid="1254323855964993144">"Rang va ko‘rinishi"</string>
<string name="night_mode" msgid="3540405868248625488">"Tungi rejim"</string>
<string name="calibrate_display" msgid="5974642573432039217">"Ekranni kalibrlash"</string>
@@ -501,10 +500,48 @@
<string name="battery_detail_charging_summary" msgid="1279095653533044008">"Quvvat tejash rejimidan quvvatlash vaqtida foydalanib bo‘lmaydi"</string>
<string name="battery_detail_switch_title" msgid="6285872470260795421">"Quvvat tejash rejimi"</string>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"Unumdorlik pasayadi va fonda internetdan foydalanish cheklanadi"</string>
+ <string name="keyboard_key_button_template" msgid="6230056639734377300">"<xliff:g id="NAME">%1$s</xliff:g> tugmasi"</string>
+ <string name="keyboard_key_home" msgid="2243500072071305073">"Bosh ekran"</string>
+ <string name="keyboard_key_back" msgid="2337450286042721351">"Orqaga"</string>
+ <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"Tepaga qaragan ko‘rsatkichli chiziq"</string>
+ <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"Pastga qaragan ko‘rsatkichli chiziq"</string>
+ <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"Chapga qaragan ko‘rsatkichli chiziq"</string>
+ <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"O‘ngga qaragan ko‘rsatkichli chiziq"</string>
+ <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"Markaziy ko‘rsatkichli chiziq"</string>
+ <string name="keyboard_key_tab" msgid="3871485650463164476">"Tab"</string>
+ <string name="keyboard_key_space" msgid="2499861316311153293">"Bo‘sh joy"</string>
+ <string name="keyboard_key_enter" msgid="5739632123216118137">"Enter"</string>
+ <string name="keyboard_key_backspace" msgid="1559580097512385854">"Backspace"</string>
+ <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"Ijro/Pauza"</string>
+ <string name="keyboard_key_media_stop" msgid="2859963958595908962">"To‘xtatish"</string>
+ <string name="keyboard_key_media_next" msgid="1894394911630345607">"Keyingi"</string>
+ <string name="keyboard_key_media_previous" msgid="4256072387192967261">"Avvalgi"</string>
+ <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"Orqaga qaytarish"</string>
+ <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"Oldinga o‘tkazish"</string>
+ <string name="keyboard_key_page_up" msgid="5654098530106845603">"Page Up"</string>
+ <string name="keyboard_key_page_down" msgid="8720502083731906136">"Page Down"</string>
+ <string name="keyboard_key_forward_del" msgid="1391451334716490176">"Delete"</string>
+ <string name="keyboard_key_move_home" msgid="2765693292069487486">"Home"</string>
+ <string name="keyboard_key_move_end" msgid="5901174332047975247">"End"</string>
+ <string name="keyboard_key_insert" msgid="8530501581636082614">"Insert"</string>
+ <string name="keyboard_key_num_lock" msgid="5052537581246772117">"Num Lock"</string>
+ <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"Raqamli klaviatura (<xliff:g id="NAME">%1$s</xliff:g>)"</string>
<string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"Tizim"</string>
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Bosh ekran"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"So‘nggi ishlatilganlar"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Orqaga"</string>
+ <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Bildirishnomalar"</string>
+ <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"Tezkor tugmalar"</string>
+ <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"Matn kiritish usulini o‘zgartirish"</string>
+ <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"Ilovalar"</string>
+ <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"Yordamchi"</string>
+ <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"Brauzer"</string>
+ <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"Kontaktlar"</string>
+ <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"E-pochta"</string>
+ <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"IM"</string>
+ <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"Musiqa"</string>
+ <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+ <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"Taqvim"</string>
<string name="tuner_full_zen_title" msgid="4540823317772234308">"Ovoz balandligini boshqarish tugmalari bilan ko‘rsatish"</string>
<string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Bezovta qilinmasin"</string>
<string name="volume_dnd_silent" msgid="4363882330723050727">"Ovoz balandligini boshqarish tugmalari"</string>
@@ -540,8 +577,7 @@
<string name="select_keycode" msgid="7413765103381924584">"Klaviatura tugmasini tanlang"</string>
<string name="preview" msgid="9077832302472282938">"Oldindan ko‘rish"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"Fragmentlar qo‘shish uchun torting"</string>
- <!-- no translation found for drag_to_remove_tiles (3361212377437088062) -->
- <skip />
+ <string name="drag_to_remove_tiles" msgid="3361212377437088062">"O‘chirish uchun bu yerga torting"</string>
<string name="qs_edit" msgid="2232596095725105230">"Tahrirlash"</string>
<string name="tuner_time" msgid="6572217313285536011">"Vaqt"</string>
<string-array name="clock_options">
@@ -560,4 +596,14 @@
<string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Tepaga siljitish"</string>
<string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Chapga siljitish"</string>
<string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"O‘ngga siljitish"</string>
+ <string name="forced_resizable_info_text" msgid="7591061837558867999">"Ilova ko‘p oynali rejimni qo‘llab-quvvatlamaydi"</string>
+ <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"<xliff:g id="POSITION">%1$d</xliff:g>-joy, “<xliff:g id="TILE_NAME">%2$s</xliff:g>” tugmasi. Tahrirlash uchun ustiga ikki marta bosing."</string>
+ <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"“<xliff:g id="TILE_NAME">%1$s</xliff:g>” tugmasi. Qo‘shish uchun ustiga ikki marta bosing."</string>
+ <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"Joylashuv: <xliff:g id="POSITION">%1$d</xliff:g>. Belgilash uchun ustiga ikki marta bosing."</string>
+ <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"“<xliff:g id="TILE_NAME">%1$s</xliff:g>” tugmasini ko‘chirish"</string>
+ <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"“<xliff:g id="TILE_NAME">%1$s</xliff:g>” tugmasini o‘chirish"</string>
+ <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"“<xliff:g id="TILE_NAME">%1$s</xliff:g>” tugmasi endi <xliff:g id="POSITION">%2$d</xliff:g>-joyni egallamoqda"</string>
+ <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"“<xliff:g id="TILE_NAME">%1$s</xliff:g>” tugmasi o‘chirildi"</string>
+ <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"“<xliff:g id="TILE_NAME">%1$s</xliff:g>” tugmasi endi <xliff:g id="POSITION">%2$d</xliff:g>-joyni egallanmoqda"</string>
+ <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Tezkor sozlamalar muharriri"</string>
</resources>
diff --git a/packages/SystemUI/res/values-uz-rUZ/strings_tv.xml b/packages/SystemUI/res/values-uz-rUZ/strings_tv.xml
index 3a4d176..9300aaa 100644
--- a/packages/SystemUI/res/values-uz-rUZ/strings_tv.xml
+++ b/packages/SystemUI/res/values-uz-rUZ/strings_tv.xml
@@ -26,6 +26,5 @@
<string name="pip_hold_home" msgid="340086535668778109">"“Kadr ichida kadr” rejimini boshqarish uchun "<b>"BOSHI"</b>" tugmasini bosib turing"</string>
<string name="pip_onboarding_description" msgid="2882896641362814195">"“Kadr ichida kadr” rejimini boshqarish uchun BOSHIGA tugmasini bosib turing"</string>
<string name="pip_onboarding_button" msgid="3957426748484904611">"OK"</string>
- <!-- no translation found for recents_tv_dismiss (3555093879593377731) -->
- <skip />
+ <string name="recents_tv_dismiss" msgid="3555093879593377731">"Yopish"</string>
</resources>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index edd0a8b..ca7c59b 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -168,6 +168,8 @@
<string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Xóa bỏ <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> đã bị loại bỏ."</string>
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Đã bỏ qua tất cả các ứng dụng gần đây."</string>
+ <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+ <skip />
<string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Bắt đầu <xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
<string name="accessibility_notification_dismissed" msgid="854211387186306927">"Đã loại bỏ thông báo."</string>
@@ -236,8 +238,7 @@
<string name="gps_notification_found_text" msgid="4619274244146446464">"Vị trí đặt bởi GPS"</string>
<string name="accessibility_location_active" msgid="2427290146138169014">"Yêu cầu về thông tin vị trí đang hoạt động"</string>
<string name="accessibility_clear_all" msgid="5235938559247164925">"Xóa tất cả thông báo."</string>
- <!-- no translation found for notification_group_overflow_indicator (1863231301642314183) -->
- <skip />
+ <string name="notification_group_overflow_indicator" msgid="1863231301642314183">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string>
<string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"Cài đặt thông báo"</string>
<string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"Cài đặt <xliff:g id="APP_NAME">%s</xliff:g>"</string>
<string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Màn hình sẽ xoay tự động."</string>
@@ -310,8 +311,7 @@
<string name="recents_search_bar_label" msgid="8074997400187836677">"tìm kiếm"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"Không thể khởi động <xliff:g id="APP">%s</xliff:g>."</string>
<string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g> bị tắt ở chế độ an toàn."</string>
- <string name="recents_history_button_label" msgid="5153358867807604821">"Lịch sử"</string>
- <string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Xóa"</string>
+ <string name="recents_stack_action_button_label" msgid="6593727103310426253">"Xóa tất cả"</string>
<string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"Ứng dụng này không hỗ trợ chế độ nhiều cửa sổ"</string>
<string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"Ứng dụng không hỗ trợ chế độ nhiều cửa sổ"</string>
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Phân tách ngang"</string>
@@ -480,8 +480,7 @@
<string name="notification_importance_max" msgid="5806278962376556491">"Hiển thị ở đầu danh sách thông báo, hiển thị trên màn hình và phát ra âm thanh"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Cài đặt khác"</string>
<string name="notification_done" msgid="5279426047273930175">"Xong"</string>
- <!-- no translation found for notification_gear_accessibility (94429150213089611) -->
- <skip />
+ <string name="notification_gear_accessibility" msgid="94429150213089611">"Điều khiển thông báo <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="color_and_appearance" msgid="1254323855964993144">"Màu sắc và giao diện"</string>
<string name="night_mode" msgid="3540405868248625488">"Chế độ ban đêm"</string>
<string name="calibrate_display" msgid="5974642573432039217">"Hiệu chỉnh hiển thị"</string>
@@ -501,10 +500,48 @@
<string name="battery_detail_charging_summary" msgid="1279095653533044008">"Trình tiết kiệm pin không khả dụng trong khi sạc"</string>
<string name="battery_detail_switch_title" msgid="6285872470260795421">"Trình tiết kiệm pin"</string>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"Giảm hiệu suất và dữ liệu nền"</string>
+ <string name="keyboard_key_button_template" msgid="6230056639734377300">"Nút <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="keyboard_key_home" msgid="2243500072071305073">"Home"</string>
+ <string name="keyboard_key_back" msgid="2337450286042721351">"Quay lại"</string>
+ <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"Lên"</string>
+ <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"Xuống"</string>
+ <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"Trái"</string>
+ <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"Phải"</string>
+ <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"Giữa"</string>
+ <string name="keyboard_key_tab" msgid="3871485650463164476">"Tab"</string>
+ <string name="keyboard_key_space" msgid="2499861316311153293">"Dấu cách"</string>
+ <string name="keyboard_key_enter" msgid="5739632123216118137">"Enter"</string>
+ <string name="keyboard_key_backspace" msgid="1559580097512385854">"Backspace"</string>
+ <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"Phát/Tạm dừng"</string>
+ <string name="keyboard_key_media_stop" msgid="2859963958595908962">"Dừng"</string>
+ <string name="keyboard_key_media_next" msgid="1894394911630345607">"Tiếp theo"</string>
+ <string name="keyboard_key_media_previous" msgid="4256072387192967261">"Trước"</string>
+ <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"Tua lại"</string>
+ <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"Tua nhanh"</string>
+ <string name="keyboard_key_page_up" msgid="5654098530106845603">"Page Up"</string>
+ <string name="keyboard_key_page_down" msgid="8720502083731906136">"Page Down"</string>
+ <string name="keyboard_key_forward_del" msgid="1391451334716490176">"Delete"</string>
+ <string name="keyboard_key_move_home" msgid="2765693292069487486">"Home"</string>
+ <string name="keyboard_key_move_end" msgid="5901174332047975247">"Cuối"</string>
+ <string name="keyboard_key_insert" msgid="8530501581636082614">"Insert"</string>
+ <string name="keyboard_key_num_lock" msgid="5052537581246772117">"Num Lock"</string>
+ <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"Bàn phím số <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"Hệ thống"</string>
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Màn hình chính"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Gần đây"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Quay lại"</string>
+ <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Thông báo"</string>
+ <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"Phím tắt"</string>
+ <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"Chuyển phương thức nhập"</string>
+ <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"Ứng dụng"</string>
+ <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"Trợ lý"</string>
+ <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"Trình duyệt"</string>
+ <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"Danh bạ"</string>
+ <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"Email"</string>
+ <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"Nhắn tin nhanh"</string>
+ <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"Âm nhạc"</string>
+ <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+ <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"Lịch"</string>
<string name="tuner_full_zen_title" msgid="4540823317772234308">"Hiển thị với các điều khiển âm lượng"</string>
<string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Không làm phiền"</string>
<string name="volume_dnd_silent" msgid="4363882330723050727">"Phím tắt các nút âm lượng"</string>
@@ -559,4 +596,14 @@
<string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Chuyển lên"</string>
<string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Di chuyển sang trái"</string>
<string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Di chuyển sang phải"</string>
+ <string name="forced_resizable_info_text" msgid="7591061837558867999">"Ứng dụng có thể không hoạt động với nhiều cửa sổ"</string>
+ <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"Vị trí <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>. Nhấn đúp để chỉnh sửa."</string>
+ <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. Nhấn đúp để thêm."</string>
+ <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"Vị trí <xliff:g id="POSITION">%1$d</xliff:g>. Nhấn đúp để chọn."</string>
+ <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"Di chuyển <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"Xóa <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="TILE_NAME">%1$s</xliff:g> được thêm vào vị trí <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+ <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"<xliff:g id="TILE_NAME">%1$s</xliff:g> được di chuyển"</string>
+ <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="TILE_NAME">%1$s</xliff:g> được di chuyển sang vị trí <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+ <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Trình chỉnh sửa cài đặt nhanh."</string>
</resources>
diff --git a/packages/SystemUI/res/values-vi/strings_tv.xml b/packages/SystemUI/res/values-vi/strings_tv.xml
index 7a5e34a..b781503 100644
--- a/packages/SystemUI/res/values-vi/strings_tv.xml
+++ b/packages/SystemUI/res/values-vi/strings_tv.xml
@@ -26,6 +26,5 @@
<string name="pip_hold_home" msgid="340086535668778109">"Giữ "<b>"HOME"</b>" để đ.khiển PIP"</string>
<string name="pip_onboarding_description" msgid="2882896641362814195">"Bấm và giữ nút HOME để điều khiển PIP"</string>
<string name="pip_onboarding_button" msgid="3957426748484904611">"OK"</string>
- <!-- no translation found for recents_tv_dismiss (3555093879593377731) -->
- <skip />
+ <string name="recents_tv_dismiss" msgid="3555093879593377731">"Loại bỏ"</string>
</resources>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index 23fb020..d559344 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -168,6 +168,8 @@
<string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"移除<xliff:g id="APP">%s</xliff:g>。"</string>
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"已删除<xliff:g id="APP">%s</xliff:g>"</string>
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"已关闭所有最近用过的应用。"</string>
+ <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+ <skip />
<string name="accessibility_recents_item_launched" msgid="7616039892382525203">"正在启动<xliff:g id="APP">%s</xliff:g>。"</string>
<string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
<string name="accessibility_notification_dismissed" msgid="854211387186306927">"已关闭通知。"</string>
@@ -236,8 +238,7 @@
<string name="gps_notification_found_text" msgid="4619274244146446464">"已通过GPS确定位置"</string>
<string name="accessibility_location_active" msgid="2427290146138169014">"应用发出了有效位置信息请求"</string>
<string name="accessibility_clear_all" msgid="5235938559247164925">"清除所有通知。"</string>
- <!-- no translation found for notification_group_overflow_indicator (1863231301642314183) -->
- <skip />
+ <string name="notification_group_overflow_indicator" msgid="1863231301642314183">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string>
<string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"通知设置"</string>
<string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"<xliff:g id="APP_NAME">%s</xliff:g>设置"</string>
<string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"屏幕会自动旋转。"</string>
@@ -310,8 +311,7 @@
<string name="recents_search_bar_label" msgid="8074997400187836677">"搜索"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"无法启动<xliff:g id="APP">%s</xliff:g>。"</string>
<string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g>已在安全模式下停用。"</string>
- <string name="recents_history_button_label" msgid="5153358867807604821">"历史记录"</string>
- <string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"清除"</string>
+ <string name="recents_stack_action_button_label" msgid="6593727103310426253">"全部清除"</string>
<string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"此应用不支持多窗口模式"</string>
<string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"应用不支持多窗口模式"</string>
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"水平分割"</string>
@@ -480,8 +480,7 @@
<string name="notification_importance_max" msgid="5806278962376556491">"在通知列表顶部显示,同时在屏幕上短暂显示,并允许发出提示音"</string>
<string name="notification_more_settings" msgid="816306283396553571">"更多设置"</string>
<string name="notification_done" msgid="5279426047273930175">"完成"</string>
- <!-- no translation found for notification_gear_accessibility (94429150213089611) -->
- <skip />
+ <string name="notification_gear_accessibility" msgid="94429150213089611">"<xliff:g id="APP_NAME">%1$s</xliff:g>通知设置"</string>
<string name="color_and_appearance" msgid="1254323855964993144">"颜色和外观"</string>
<string name="night_mode" msgid="3540405868248625488">"夜间模式"</string>
<string name="calibrate_display" msgid="5974642573432039217">"校准显示画面"</string>
@@ -501,10 +500,60 @@
<string name="battery_detail_charging_summary" msgid="1279095653533044008">"充电过程中无法使用节电助手"</string>
<string name="battery_detail_switch_title" msgid="6285872470260795421">"节电助手"</string>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"降低性能并限制后台流量"</string>
+ <string name="keyboard_key_button_template" msgid="6230056639734377300">"<xliff:g id="NAME">%1$s</xliff:g>按钮"</string>
+ <string name="keyboard_key_home" msgid="2243500072071305073">"Home"</string>
+ <string name="keyboard_key_back" msgid="2337450286042721351">"返回"</string>
+ <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"向上"</string>
+ <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"向下"</string>
+ <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"向左"</string>
+ <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"向右"</string>
+ <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"中心"</string>
+ <string name="keyboard_key_tab" msgid="3871485650463164476">"Tab"</string>
+ <string name="keyboard_key_space" msgid="2499861316311153293">"空格"</string>
+ <string name="keyboard_key_enter" msgid="5739632123216118137">"Enter"</string>
+ <string name="keyboard_key_backspace" msgid="1559580097512385854">"退格"</string>
+ <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"播放/暂停"</string>
+ <string name="keyboard_key_media_stop" msgid="2859963958595908962">"停止"</string>
+ <string name="keyboard_key_media_next" msgid="1894394911630345607">"下一曲"</string>
+ <string name="keyboard_key_media_previous" msgid="4256072387192967261">"上一曲"</string>
+ <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"快退"</string>
+ <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"快进"</string>
+ <string name="keyboard_key_page_up" msgid="5654098530106845603">"向上翻页"</string>
+ <string name="keyboard_key_page_down" msgid="8720502083731906136">"向下翻页"</string>
+ <string name="keyboard_key_forward_del" msgid="1391451334716490176">"删除"</string>
+ <string name="keyboard_key_move_home" msgid="2765693292069487486">"Home"</string>
+ <string name="keyboard_key_move_end" msgid="5901174332047975247">"End"</string>
+ <string name="keyboard_key_insert" msgid="8530501581636082614">"Insert"</string>
+ <string name="keyboard_key_num_lock" msgid="5052537581246772117">"Num Lock"</string>
+ <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"数字键盘 <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"系统"</string>
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"主屏幕"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"最近"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"返回"</string>
+ <!-- no translation found for keyboard_shortcut_group_system_notifications (8366964080041773224) -->
+ <skip />
+ <!-- no translation found for keyboard_shortcut_group_system_shortcuts_helper (4892255911160332762) -->
+ <skip />
+ <!-- no translation found for keyboard_shortcut_group_system_switch_input (2334164096341310324) -->
+ <skip />
+ <!-- no translation found for keyboard_shortcut_group_applications (9129465955073449206) -->
+ <skip />
+ <!-- no translation found for keyboard_shortcut_group_applications_assist (9095441910537146013) -->
+ <skip />
+ <!-- no translation found for keyboard_shortcut_group_applications_browser (6465985474000766533) -->
+ <skip />
+ <!-- no translation found for keyboard_shortcut_group_applications_contacts (2064197111278436375) -->
+ <skip />
+ <!-- no translation found for keyboard_shortcut_group_applications_email (6257036897441939004) -->
+ <skip />
+ <!-- no translation found for keyboard_shortcut_group_applications_im (1892749399083161405) -->
+ <skip />
+ <!-- no translation found for keyboard_shortcut_group_applications_music (4775559515850922780) -->
+ <skip />
+ <!-- no translation found for keyboard_shortcut_group_applications_youtube (6555453761294723317) -->
+ <skip />
+ <!-- no translation found for keyboard_shortcut_group_applications_calendar (9043614299194991263) -->
+ <skip />
<string name="tuner_full_zen_title" msgid="4540823317772234308">"与音量控件一起显示"</string>
<string name="volume_and_do_not_disturb" msgid="3373784330208603030">"请勿打扰"</string>
<string name="volume_dnd_silent" msgid="4363882330723050727">"音量按钮快捷键"</string>
@@ -559,4 +608,14 @@
<string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"上移"</string>
<string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"左移"</string>
<string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"右移"</string>
+ <string name="forced_resizable_info_text" msgid="7591061837558867999">"应用可能无法在多窗口模式下正常运行"</string>
+ <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"位置 <xliff:g id="POSITION">%1$d</xliff:g>,<xliff:g id="TILE_NAME">%2$s</xliff:g>。点按两次即可修改。"</string>
+ <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>。点按两次即可添加。"</string>
+ <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"位置 <xliff:g id="POSITION">%1$d</xliff:g>。点按两次即可选择。"</string>
+ <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"移动<xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"移除<xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"已将<xliff:g id="TILE_NAME">%1$s</xliff:g>添加到位置 <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+ <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"已移除<xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"已将<xliff:g id="TILE_NAME">%1$s</xliff:g>移至位置 <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+ <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"快捷设置编辑器。"</string>
</resources>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings_tv.xml b/packages/SystemUI/res/values-zh-rCN/strings_tv.xml
index 2bfe478..77d3bff 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings_tv.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings_tv.xml
@@ -26,6 +26,5 @@
<string name="pip_hold_home" msgid="340086535668778109">"按住"<b>"主屏幕"</b>"按钮即可控制画中画功能"</string>
<string name="pip_onboarding_description" msgid="2882896641362814195">"按住主屏幕按钮即可控制画中画功能"</string>
<string name="pip_onboarding_button" msgid="3957426748484904611">"知道了"</string>
- <!-- no translation found for recents_tv_dismiss (3555093879593377731) -->
- <skip />
+ <string name="recents_tv_dismiss" msgid="3555093879593377731">"关闭"</string>
</resources>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index 902cf71..083cd5e 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -168,6 +168,8 @@
<string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"關閉「<xliff:g id="APP">%s</xliff:g>」。"</string>
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"「<xliff:g id="APP">%s</xliff:g>」已關閉。"</string>
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"所有最近使用的應用程式均已關閉。"</string>
+ <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+ <skip />
<string name="accessibility_recents_item_launched" msgid="7616039892382525203">"正在啟動「<xliff:g id="APP">%s</xliff:g>」。"</string>
<string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g><xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
<string name="accessibility_notification_dismissed" msgid="854211387186306927">"通知已關閉。"</string>
@@ -309,8 +311,7 @@
<string name="recents_search_bar_label" msgid="8074997400187836677">"搜尋"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"無法啟動「<xliff:g id="APP">%s</xliff:g>」。"</string>
<string name="recents_launch_disabled_message" msgid="1624523193008871793">"「<xliff:g id="APP">%s</xliff:g>」已在安全模式中停用。"</string>
- <string name="recents_history_button_label" msgid="5153358867807604821">"記錄"</string>
- <string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"清除"</string>
+ <string name="recents_stack_action_button_label" msgid="6593727103310426253">"全部清除"</string>
<string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"此應用程式不支援多視窗模式"</string>
<string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"應用程式不支援多視窗模式"</string>
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"水平分割"</string>
@@ -499,10 +500,48 @@
<string name="battery_detail_charging_summary" msgid="1279095653533044008">"充電時無法使用「省電模式」"</string>
<string name="battery_detail_switch_title" msgid="6285872470260795421">"省電模式"</string>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"降低效能並限制背景數據傳輸"</string>
+ <string name="keyboard_key_button_template" msgid="6230056639734377300">"<xliff:g id="NAME">%1$s</xliff:g> 鍵"</string>
+ <string name="keyboard_key_home" msgid="2243500072071305073">"Home"</string>
+ <string name="keyboard_key_back" msgid="2337450286042721351">"返回"</string>
+ <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"向上"</string>
+ <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"向下"</string>
+ <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"向左"</string>
+ <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"向右"</string>
+ <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"箭咀中央"</string>
+ <string name="keyboard_key_tab" msgid="3871485650463164476">"Tab"</string>
+ <string name="keyboard_key_space" msgid="2499861316311153293">"空格"</string>
+ <string name="keyboard_key_enter" msgid="5739632123216118137">"輸入 (Enter)"</string>
+ <string name="keyboard_key_backspace" msgid="1559580097512385854">"Backspace"</string>
+ <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"播放/暫停"</string>
+ <string name="keyboard_key_media_stop" msgid="2859963958595908962">"停止"</string>
+ <string name="keyboard_key_media_next" msgid="1894394911630345607">"下一首"</string>
+ <string name="keyboard_key_media_previous" msgid="4256072387192967261">"上一首"</string>
+ <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"倒帶"</string>
+ <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"向前快轉"</string>
+ <string name="keyboard_key_page_up" msgid="5654098530106845603">"上一頁"</string>
+ <string name="keyboard_key_page_down" msgid="8720502083731906136">"下一頁"</string>
+ <string name="keyboard_key_forward_del" msgid="1391451334716490176">"刪除"</string>
+ <string name="keyboard_key_move_home" msgid="2765693292069487486">"Home"</string>
+ <string name="keyboard_key_move_end" msgid="5901174332047975247">"End"</string>
+ <string name="keyboard_key_insert" msgid="8530501581636082614">"插入"</string>
+ <string name="keyboard_key_num_lock" msgid="5052537581246772117">"數字鎖定"</string>
+ <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"數字鍵盤 <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"系統"</string>
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"主畫面"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"最近的活動"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"返回"</string>
+ <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"通知"</string>
+ <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"鍵盤快速鍵"</string>
+ <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"切換輸入法"</string>
+ <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"應用程式"</string>
+ <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"輔助"</string>
+ <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"瀏覽器"</string>
+ <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"通訊錄"</string>
+ <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"電郵"</string>
+ <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"即時通訊"</string>
+ <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"音樂"</string>
+ <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+ <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"日曆"</string>
<string name="tuner_full_zen_title" msgid="4540823317772234308">"與音量控制一起顯示"</string>
<string name="volume_and_do_not_disturb" msgid="3373784330208603030">"請勿騷擾"</string>
<string name="volume_dnd_silent" msgid="4363882330723050727">"音量按鈕快速鍵"</string>
@@ -557,4 +596,14 @@
<string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"向上移"</string>
<string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"向左移"</string>
<string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"向右移"</string>
+ <string name="forced_resizable_info_text" msgid="7591061837558867999">"應用程式可能無法在多重視窗下運作"</string>
+ <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"位置 <xliff:g id="POSITION">%1$d</xliff:g>,<xliff:g id="TILE_NAME">%2$s</xliff:g>。輕按兩下即可編輯。"</string>
+ <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>。輕按兩下即可新增。"</string>
+ <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"位置 <xliff:g id="POSITION">%1$d</xliff:g>。輕按兩下即可選取。"</string>
+ <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"移動 <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"移除 <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="TILE_NAME">%1$s</xliff:g> 已新增至位置 <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+ <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"<xliff:g id="TILE_NAME">%1$s</xliff:g> 已移除"</string>
+ <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="TILE_NAME">%1$s</xliff:g> 已移至位置 <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+ <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"快速設定編輯工具。"</string>
</resources>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index ea32930..3c95a93 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -168,6 +168,8 @@
<string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"關閉「<xliff:g id="APP">%s</xliff:g>」。"</string>
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"「<xliff:g id="APP">%s</xliff:g>」已關閉。"</string>
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"最近使用的應用程式已全部關閉。"</string>
+ <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+ <skip />
<string name="accessibility_recents_item_launched" msgid="7616039892382525203">"正在啟動「<xliff:g id="APP">%s</xliff:g>」。"</string>
<string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
<string name="accessibility_notification_dismissed" msgid="854211387186306927">"已關閉通知。"</string>
@@ -236,8 +238,7 @@
<string name="gps_notification_found_text" msgid="4619274244146446464">"GPS 已定位"</string>
<string name="accessibility_location_active" msgid="2427290146138169014">"有位置資訊要求"</string>
<string name="accessibility_clear_all" msgid="5235938559247164925">"清除所有通知。"</string>
- <!-- no translation found for notification_group_overflow_indicator (1863231301642314183) -->
- <skip />
+ <string name="notification_group_overflow_indicator" msgid="1863231301642314183">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string>
<string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"通知設定"</string>
<string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"<xliff:g id="APP_NAME">%s</xliff:g>設定"</string>
<string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"螢幕會自動旋轉。"</string>
@@ -310,8 +311,7 @@
<string name="recents_search_bar_label" msgid="8074997400187836677">"搜尋"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"無法啟動「<xliff:g id="APP">%s</xliff:g>」。"</string>
<string name="recents_launch_disabled_message" msgid="1624523193008871793">"「<xliff:g id="APP">%s</xliff:g>」在安全模式中為停用狀態。"</string>
- <string name="recents_history_button_label" msgid="5153358867807604821">"紀錄"</string>
- <string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"清除"</string>
+ <string name="recents_stack_action_button_label" msgid="6593727103310426253">"全部清除"</string>
<string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"這個應用程式不支援多視窗模式"</string>
<string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"應用程式不支援多視窗模式"</string>
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"水平分割"</string>
@@ -480,8 +480,7 @@
<string name="notification_importance_max" msgid="5806278962376556491">"顯示在通知清單頂端,同時短暫顯示在畫面上並發出音效"</string>
<string name="notification_more_settings" msgid="816306283396553571">"更多設定"</string>
<string name="notification_done" msgid="5279426047273930175">"完成"</string>
- <!-- no translation found for notification_gear_accessibility (94429150213089611) -->
- <skip />
+ <string name="notification_gear_accessibility" msgid="94429150213089611">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」通知控制項"</string>
<string name="color_and_appearance" msgid="1254323855964993144">"顏色和外觀"</string>
<string name="night_mode" msgid="3540405868248625488">"夜間模式"</string>
<string name="calibrate_display" msgid="5974642573432039217">"校正顯示畫面"</string>
@@ -501,10 +500,48 @@
<string name="battery_detail_charging_summary" msgid="1279095653533044008">"充電時無法使用節約耗電量模式"</string>
<string name="battery_detail_switch_title" msgid="6285872470260795421">"節約耗電量"</string>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"降低效能並限制背景資料傳輸"</string>
+ <string name="keyboard_key_button_template" msgid="6230056639734377300">"<xliff:g id="NAME">%1$s</xliff:g> 按鈕"</string>
+ <string name="keyboard_key_home" msgid="2243500072071305073">"Home 鍵"</string>
+ <string name="keyboard_key_back" msgid="2337450286042721351">"返回"</string>
+ <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"向上鍵"</string>
+ <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"向下鍵"</string>
+ <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"向左鍵"</string>
+ <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"向右鍵"</string>
+ <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"中央鍵"</string>
+ <string name="keyboard_key_tab" msgid="3871485650463164476">"Tab 鍵"</string>
+ <string name="keyboard_key_space" msgid="2499861316311153293">"空格鍵"</string>
+ <string name="keyboard_key_enter" msgid="5739632123216118137">"Enter 鍵"</string>
+ <string name="keyboard_key_backspace" msgid="1559580097512385854">"Backspace 鍵"</string>
+ <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"播放/暫停"</string>
+ <string name="keyboard_key_media_stop" msgid="2859963958595908962">"停止"</string>
+ <string name="keyboard_key_media_next" msgid="1894394911630345607">"下一個"</string>
+ <string name="keyboard_key_media_previous" msgid="4256072387192967261">"上一個"</string>
+ <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"倒轉"</string>
+ <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"快轉"</string>
+ <string name="keyboard_key_page_up" msgid="5654098530106845603">"Page Up 鍵"</string>
+ <string name="keyboard_key_page_down" msgid="8720502083731906136">"Page Down 鍵"</string>
+ <string name="keyboard_key_forward_del" msgid="1391451334716490176">"Delete 鍵"</string>
+ <string name="keyboard_key_move_home" msgid="2765693292069487486">"Home 鍵"</string>
+ <string name="keyboard_key_move_end" msgid="5901174332047975247">"End 鍵"</string>
+ <string name="keyboard_key_insert" msgid="8530501581636082614">"Insert 鍵"</string>
+ <string name="keyboard_key_num_lock" msgid="5052537581246772117">"Num Lock 鍵"</string>
+ <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"數字鍵 <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"系統"</string>
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"主畫面"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"近期活動"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"返回"</string>
+ <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"通知"</string>
+ <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"鍵盤快速鍵"</string>
+ <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"切換輸入法"</string>
+ <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"應用程式"</string>
+ <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"小幫手"</string>
+ <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"瀏覽器"</string>
+ <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"聯絡人"</string>
+ <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"電子郵件"</string>
+ <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"即時訊息"</string>
+ <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"音樂"</string>
+ <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
+ <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"日曆"</string>
<string name="tuner_full_zen_title" msgid="4540823317772234308">"與音量控制項一起顯示"</string>
<string name="volume_and_do_not_disturb" msgid="3373784330208603030">"零打擾"</string>
<string name="volume_dnd_silent" msgid="4363882330723050727">"音量按鈕快速鍵"</string>
@@ -559,4 +596,14 @@
<string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"向上移"</string>
<string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"向左移"</string>
<string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"向右移"</string>
+ <string name="forced_resizable_info_text" msgid="7591061837558867999">"應用程式可能無法在多視窗模式下運作"</string>
+ <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"位置 <xliff:g id="POSITION">%1$d</xliff:g>,<xliff:g id="TILE_NAME">%2$s</xliff:g>。輕按兩下即可編輯。"</string>
+ <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>。輕按兩下即可新增。"</string>
+ <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"位置 <xliff:g id="POSITION">%1$d</xliff:g>。輕按兩下即可選取。"</string>
+ <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"移動 <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"移除 <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"已將 <xliff:g id="TILE_NAME">%1$s</xliff:g> 新增到位置 <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+ <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"已移除 <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"已將 <xliff:g id="TILE_NAME">%1$s</xliff:g> 移到位置 <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+ <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"快速設定編輯器。"</string>
</resources>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings_tv.xml b/packages/SystemUI/res/values-zh-rTW/strings_tv.xml
index a6744e7..4420d87 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings_tv.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings_tv.xml
@@ -26,6 +26,5 @@
<string name="pip_hold_home" msgid="340086535668778109">"按住「主畫面」"<b></b>"按鈕即可控制子母畫面"</string>
<string name="pip_onboarding_description" msgid="2882896641362814195">"按住「主畫面」按鈕即可控制子母畫面"</string>
<string name="pip_onboarding_button" msgid="3957426748484904611">"我知道了"</string>
- <!-- no translation found for recents_tv_dismiss (3555093879593377731) -->
- <skip />
+ <string name="recents_tv_dismiss" msgid="3555093879593377731">"關閉"</string>
</resources>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index 9f8f298..e03e642 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -168,6 +168,8 @@
<string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Cashisa i-<xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> ivaliwe."</string>
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Zonke izinhlelo zokusebenza zakamuva zicashisiwe."</string>
+ <!-- no translation found for accessibility_recents_item_open_app_info (5107479759905883540) -->
+ <skip />
<string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Iqala i-<xliff:g id="APP">%s</xliff:g>."</string>
<string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
<string name="accessibility_notification_dismissed" msgid="854211387186306927">"Isaziso sichithiwe."</string>
@@ -236,8 +238,7 @@
<string name="gps_notification_found_text" msgid="4619274244146446464">"Indawo ihlelwe i-GPS"</string>
<string name="accessibility_location_active" msgid="2427290146138169014">"Izicelo zendawo ziyasebenza"</string>
<string name="accessibility_clear_all" msgid="5235938559247164925">"Susa zonke izaziso."</string>
- <!-- no translation found for notification_group_overflow_indicator (1863231301642314183) -->
- <skip />
+ <string name="notification_group_overflow_indicator" msgid="1863231301642314183">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string>
<string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"Izilungiselelo zesaziso"</string>
<string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"<xliff:g id="APP_NAME">%s</xliff:g> izilungiselelo"</string>
<string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Isikrini sizophenduka ngokuzenzakalela."</string>
@@ -310,8 +311,7 @@
<string name="recents_search_bar_label" msgid="8074997400187836677">"sesha"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"Ayikwazanga ukuqala i-<xliff:g id="APP">%s</xliff:g>."</string>
<string name="recents_launch_disabled_message" msgid="1624523193008871793">"I-<xliff:g id="APP">%s</xliff:g> ikhutshaziwe kumodi yokuphepha."</string>
- <string name="recents_history_button_label" msgid="5153358867807604821">"Umlando"</string>
- <string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Sula"</string>
+ <string name="recents_stack_action_button_label" msgid="6593727103310426253">"Sula konke"</string>
<string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"Lolu hlelo lokusebenza alusekeli amawindi amaningi"</string>
<string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"Uhlelo lokusebenza alusekeli amawindi amaningi"</string>
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Hlukanisa okuvundlile"</string>
@@ -480,8 +480,7 @@
<string name="notification_importance_max" msgid="5806278962376556491">"Bonisa phezulu kohlu lwezaziso, beka phezu kwesikrini futhi uvumele umsindo"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Izilungiselelo eziningi"</string>
<string name="notification_done" msgid="5279426047273930175">"Kwenziwe"</string>
- <!-- no translation found for notification_gear_accessibility (94429150213089611) -->
- <skip />
+ <string name="notification_gear_accessibility" msgid="94429150213089611">"<xliff:g id="APP_NAME">%1$s</xliff:g> izilawuli zasaziso"</string>
<string name="color_and_appearance" msgid="1254323855964993144">"Umbala nokubonakala"</string>
<string name="night_mode" msgid="3540405868248625488">"Imodi yasebusuku"</string>
<string name="calibrate_display" msgid="5974642573432039217">"Sika isibonisi"</string>
@@ -501,10 +500,48 @@
<string name="battery_detail_charging_summary" msgid="1279095653533044008">"Isilondolozi sebhethri asitholakali ngesikhathi sokushaja"</string>
<string name="battery_detail_switch_title" msgid="6285872470260795421">"Isilondolozi sebhethri"</string>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"Sehlisa ukusebenza nedatha yasemuva"</string>
+ <string name="keyboard_key_button_template" msgid="6230056639734377300">"Inkinobho <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="keyboard_key_home" msgid="2243500072071305073">"Ekhaya"</string>
+ <string name="keyboard_key_back" msgid="2337450286042721351">"Emuva"</string>
+ <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"Phezulu"</string>
+ <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"Phansi"</string>
+ <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"Kwesobunxele"</string>
+ <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"Kwesokudla"</string>
+ <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"Maphakathi"</string>
+ <string name="keyboard_key_tab" msgid="3871485650463164476">"Ithebhu"</string>
+ <string name="keyboard_key_space" msgid="2499861316311153293">"Isikhala"</string>
+ <string name="keyboard_key_enter" msgid="5739632123216118137">"Faka"</string>
+ <string name="keyboard_key_backspace" msgid="1559580097512385854">"Isikhala"</string>
+ <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"Dlala/Misa okwesikhashana"</string>
+ <string name="keyboard_key_media_stop" msgid="2859963958595908962">"Misa"</string>
+ <string name="keyboard_key_media_next" msgid="1894394911630345607">"Okulandelayo"</string>
+ <string name="keyboard_key_media_previous" msgid="4256072387192967261">"Okwangaphambilini"</string>
+ <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"Buyisela emuva"</string>
+ <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"Iya phambili ngokushesha"</string>
+ <string name="keyboard_key_page_up" msgid="5654098530106845603">"Ikhasi phezulu"</string>
+ <string name="keyboard_key_page_down" msgid="8720502083731906136">"Ikhasi phansi"</string>
+ <string name="keyboard_key_forward_del" msgid="1391451334716490176">"Susa"</string>
+ <string name="keyboard_key_move_home" msgid="2765693292069487486">"Ekhaya"</string>
+ <string name="keyboard_key_move_end" msgid="5901174332047975247">"Phelisa"</string>
+ <string name="keyboard_key_insert" msgid="8530501581636082614">"Faka"</string>
+ <string name="keyboard_key_num_lock" msgid="5052537581246772117">"Izinombolo"</string>
+ <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"Phedi yezinombolo <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"Isistimu"</string>
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Ekhaya"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Okwakamuva"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Emuva"</string>
+ <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Izaziso"</string>
+ <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"Izinqamulelo Zekhibhodi"</string>
+ <string name="keyboard_shortcut_group_system_switch_input" msgid="2334164096341310324">"Shintsha indlela yokufaka"</string>
+ <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"Izinhlelo zokusebenza"</string>
+ <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"Siza"</string>
+ <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"Isiphequluli"</string>
+ <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"Oxhumana nabo"</string>
+ <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"I-imeyili"</string>
+ <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"I-IM"</string>
+ <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"Umculo"</string>
+ <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"I-YouTube"</string>
+ <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"Ikhalenda"</string>
<string name="tuner_full_zen_title" msgid="4540823317772234308">"Bonisa ngezilawuli zevolomu"</string>
<string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Ungaphazamisi"</string>
<string name="volume_dnd_silent" msgid="4363882330723050727">"Izinqamuleli zezinkinobho zevolomu"</string>
@@ -559,4 +596,14 @@
<string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Iya phezulu"</string>
<string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Iya kwesokunxele"</string>
<string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Iya kwesokudla"</string>
+ <string name="forced_resizable_info_text" msgid="7591061837558867999">"Uhlelo lokusebenza kungenzeka lungasebenzi namawindi amaningi"</string>
+ <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"Isimo esingu-<xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>. Thepha kabili ukuze uhlele."</string>
+ <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. Thepha kabili ukuze ungeze."</string>
+ <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"Isimo esingu-<xliff:g id="POSITION">%1$d</xliff:g>. Thepha kabili ukuze ukhethe."</string>
+ <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"Hambisa i-<xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"Susa i-<xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"I-<xliff:g id="TILE_NAME">%1$s</xliff:g> ingezwe kusimo esingu-<xliff:g id="POSITION">%2$d</xliff:g>"</string>
+ <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"I-<xliff:g id="TILE_NAME">%1$s</xliff:g> isusiwe"</string>
+ <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"I-<xliff:g id="TILE_NAME">%1$s</xliff:g> ihanjiswe kusimo esingu-<xliff:g id="POSITION">%2$d</xliff:g>"</string>
+ <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Isihleli sezilungiselelo ezisheshayo."</string>
</resources>
diff --git a/packages/SystemUI/res/values-zu/strings_tv.xml b/packages/SystemUI/res/values-zu/strings_tv.xml
index 5fb063d..1904237 100644
--- a/packages/SystemUI/res/values-zu/strings_tv.xml
+++ b/packages/SystemUI/res/values-zu/strings_tv.xml
@@ -26,6 +26,5 @@
<string name="pip_hold_home" msgid="340086535668778109">"Bamba "<b>"IKHAYA"</b>" ukuze ulawule i-PIP"</string>
<string name="pip_onboarding_description" msgid="2882896641362814195">"Cindezela futhi ubambe inkinobho EKHAYA ukuze ulawule i-PIP"</string>
<string name="pip_onboarding_button" msgid="3957426748484904611">"Ngiyezwa"</string>
- <!-- no translation found for recents_tv_dismiss (3555093879593377731) -->
- <skip />
+ <string name="recents_tv_dismiss" msgid="3555093879593377731">"Cashisa"</string>
</resources>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 622ae71..fd051b1 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -153,6 +153,9 @@
<!-- The animation duration for animating the removal of a task view. -->
<integer name="recents_animate_task_view_remove_duration">175</integer>
+ <!-- The base animation duration for animating the removal of all task views. -->
+ <integer name="recents_animate_task_views_remove_all_duration">300</integer>
+
<!-- The animation duration for scrolling the stack to a particular item. -->
<integer name="recents_animate_task_stack_scroll_duration">200</integer>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 88230bc..c094da9 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -179,7 +179,8 @@
<dimen name="qs_date_collapsed_text_size">14sp</dimen>
<dimen name="qs_date_text_size">16sp</dimen>
<dimen name="qs_header_gear_translation">16dp</dimen>
- <dimen name="qs_page_indicator_size">12dp</dimen>
+ <dimen name="qs_page_indicator_width">16dp</dimen>
+ <dimen name="qs_page_indicator_height">8dp</dimen>
<dimen name="qs_tile_icon_size">24dp</dimen>
<dimen name="qs_tile_text_size">12sp</dimen>
<dimen name="qs_tile_divider_height">1dp</dimen>
@@ -573,10 +574,12 @@
<dimen name="recents_layout_bottom_margin">16dp</dimen>
<dimen name="recents_layout_side_margin_phone">16dp</dimen>
<dimen name="recents_layout_side_margin_tablet">48dp</dimen>
+ <dimen name="recents_layout_side_margin_tablet_docked">16dp</dimen>
<dimen name="recents_layout_side_margin_tablet_xlarge">64dp</dimen>
+ <dimen name="recents_layout_side_margin_tablet_xlarge_docked">16dp</dimen>
<!-- The height between the top margin and the top of the focused task. -->
- <dimen name="recents_layout_top_peek_size">56dp</dimen>
+ <dimen name="recents_layout_top_peek_size">48dp</dimen>
<!-- The height between the bottom margin and the top of task in front of the focused task. -->
<dimen name="recents_layout_bottom_peek_size">56dp</dimen>
diff --git a/packages/SystemUI/res/values/dimens_tv.xml b/packages/SystemUI/res/values/dimens_tv.xml
index 953dd65..337513d 100644
--- a/packages/SystemUI/res/values/dimens_tv.xml
+++ b/packages/SystemUI/res/values/dimens_tv.xml
@@ -38,9 +38,6 @@
<dimen name="recents_tv_unselected_item_z">6dp</dimen>
<dimen name="recents_tv_selected_item_z_delta">10dp</dimen>
- <!-- Extra space around the PIP and its outline in PIP onboarding activity -->
- <dimen name="tv_pip_bounds_space">3dp</dimen>
-
<!-- Values for text on recents cards on tv -->
<dimen name="recents_tv_title_text_size">12sp</dimen>
@@ -52,4 +49,10 @@
<dimen name="recents_tv_dismiss_icon_bottom_margin">1dip</dimen>
<dimen name="recents_tv_dismiss_text_size">12sp</dimen>
+ <!-- Values for PIP in recents -->
+ <dimen name="recents_tv_pip_controls_margin_top">10dp</dimen>
+
+ <!-- Extra space around the PIP and its outline in PIP onboarding activity -->
+ <dimen name="tv_pip_bounds_space">3dp</dimen>
+
</resources>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 25ecd888..060e050 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -417,6 +417,8 @@
<string name="accessibility_recents_item_dismissed"><xliff:g id="app" example="Calendar">%s</xliff:g> dismissed.</string>
<!-- Content description to tell the user all applications has been removed from recents -->
<string name="accessibility_recents_all_items_dismissed">All recent applications dismissed.</string>
+ <!-- Content description to tell the user that this button will open application info for an application in recents -->
+ <string name="accessibility_recents_item_open_app_info">Open <xliff:g id="app" example="Calendar">%s</xliff:g> application info.</string>
<!-- Content description to tell the user an application has been launched from recents -->
<string name="accessibility_recents_item_launched">Starting <xliff:g id="app" example="Calendar">%s</xliff:g>.</string>
<!-- Content description of individual recents task. -->
@@ -1388,6 +1390,31 @@
<string name="keyboard_shortcut_group_system_recents">Recents</string>
<!-- User visible title for the the keyboard shortcut that triggers the back action. -->
<string name="keyboard_shortcut_group_system_back">Back</string>
+ <!-- User visible title for the the keyboard shortcut that triggers the notification shade. -->
+ <string name="keyboard_shortcut_group_system_notifications">Notifications</string>
+ <!-- User visible title for the the keyboard shortcut that triggers the keyboard shortcuts helper. -->
+ <string name="keyboard_shortcut_group_system_shortcuts_helper">Keyboard Shortcuts</string>
+ <!-- User visible title for the the keyboard shortcut that switches input methods. -->
+ <string name="keyboard_shortcut_group_system_switch_input">Switch input method</string>
+
+ <!-- User visible title for the system-wide applications keyboard shortcuts list. -->
+ <string name="keyboard_shortcut_group_applications">Applications</string>
+ <!-- User visible title for the keyboard shortcut that takes the user to the assist app. -->
+ <string name="keyboard_shortcut_group_applications_assist">Assist</string>
+ <!-- User visible title for the keyboard shortcut that takes the user to the browser app. -->
+ <string name="keyboard_shortcut_group_applications_browser">Browser</string>
+ <!-- User visible title for the keyboard shortcut that takes the user to the contacts app. -->
+ <string name="keyboard_shortcut_group_applications_contacts">Contacts</string>
+ <!-- User visible title for the keyboard shortcut that takes the user to the email app. -->
+ <string name="keyboard_shortcut_group_applications_email">Email</string>
+ <!-- User visible title for the keyboard shortcut that takes the user to the instant messaging app. -->
+ <string name="keyboard_shortcut_group_applications_im">IM</string>
+ <!-- User visible title for the keyboard shortcut that takes the user to the music app. -->
+ <string name="keyboard_shortcut_group_applications_music">Music</string>
+ <!-- User visible title for the keyboard shortcut that takes the user to the YouTube app. -->
+ <string name="keyboard_shortcut_group_applications_youtube">YouTube</string>
+ <!-- User visible title for the keyboard shortcut that takes the user to the calendar app. -->
+ <string name="keyboard_shortcut_group_applications_calendar">Calendar</string>
<!-- SysUI Tuner: Option to show full do not disturb panel in volume [CHAR LIMIT=60] -->
<string name="tuner_full_zen_title">Show with volume controls</string>
@@ -1532,4 +1559,32 @@
<!-- Text that gets shown on top of current activity to inform the user that the system force-resized the current activity and that things might crash/not work properly [CHAR LIMIT=NONE] -->
<string name="forced_resizable_info_text">App may not work with multi-window</string>
+
+ <!-- Accessibility description of a QS tile while editing positions [CHAR LIMIT=NONE] -->
+ <string name="accessibility_qs_edit_tile_label">Position <xliff:g id="position" example="2">%1$d</xliff:g>, <xliff:g id="tile_name" example="Wi-Fi">%2$s</xliff:g>. Double tap to edit.</string>
+
+ <!-- Accessibility description of a QS tile while editing positions [CHAR LIMIT=NONE] -->
+ <string name="accessibility_qs_edit_add_tile_label"><xliff:g id="tile_name" example="Wi-Fi">%1$s</xliff:g>. Double tap to add.</string>
+
+ <!-- Accessibility description of a place to drop a tile while editing positions [CHAR LIMIT=NONE] -->
+ <string name="accessibility_qs_edit_position_label">Position <xliff:g id="position" example="2">%1$d</xliff:g>. Double tap to select.</string>
+
+ <!-- Accessibility description of option to move QS tile [CHAR LIMIT=NONE] -->
+ <string name="accessibility_qs_edit_move_tile">Move <xliff:g id="tile_name" example="Wi-Fi">%1$s</xliff:g></string>
+
+ <!-- Accessibility description of option to remove QS tile [CHAR LIMIT=NONE] -->
+ <string name="accessibility_qs_edit_remove_tile">Remove <xliff:g id="tile_name" example="Wi-Fi">%1$s</xliff:g></string>
+
+ <!-- Accessibility action when QS tile is added [CHAR LIMIT=NONE] -->
+ <string name="accessibility_qs_edit_tile_added"><xliff:g id="tile_name" example="Wi-Fi">%1$s</xliff:g> is added to position <xliff:g id="position" example="5">%2$d</xliff:g></string>
+
+ <!-- Accessibility action when QS tile is removed [CHAR LIMIT=NONE] -->
+ <string name="accessibility_qs_edit_tile_removed"><xliff:g id="tile_name" example="Wi-Fi">%1$s</xliff:g> is removed</string>
+
+ <!-- Accessibility action when QS tile is moved [CHAR LIMIT=NONE] -->
+ <string name="accessibility_qs_edit_tile_moved"><xliff:g id="tile_name" example="Wi-Fi">%1$s</xliff:g> moved to position <xliff:g id="position" example="5">%2$d</xliff:g></string>
+
+ <!-- Accessibility label for window when QS editing is happening [CHAR LIMIT=NONE] -->
+ <string name="accessibility_desc_quick_settings_edit">Quick settings editor.</string>
+
</resources>
diff --git a/packages/SystemUI/res/xml/night_mode.xml b/packages/SystemUI/res/xml/night_mode.xml
index d5f5333..34af820 100644
--- a/packages/SystemUI/res/xml/night_mode.xml
+++ b/packages/SystemUI/res/xml/night_mode.xml
@@ -27,10 +27,6 @@
android:title="@string/when_night_mode_on">
<SwitchPreference
- android:key="dark_theme"
- android:title="@string/use_dark_theme" />
-
- <SwitchPreference
android:key="adjust_tint"
android:title="@string/adjust_tint" />
@@ -40,8 +36,4 @@
</PreferenceCategory>
- <Preference
- android:selectable="false"
- android:summary="@string/night_mode_disclaimer" />
-
</PreferenceScreen>
diff --git a/packages/SystemUI/src/com/android/systemui/BatteryMeterDrawable.java b/packages/SystemUI/src/com/android/systemui/BatteryMeterDrawable.java
index 4845425..087f61e 100755
--- a/packages/SystemUI/src/com/android/systemui/BatteryMeterDrawable.java
+++ b/packages/SystemUI/src/com/android/systemui/BatteryMeterDrawable.java
@@ -452,7 +452,7 @@
boolean pctOpaque = false;
float pctX = 0, pctY = 0;
String pctText = null;
- if (!mPluggedIn && level > mCriticalLevel && mShowPercent) {
+ if (!mPluggedIn && !mPowerSaveEnabled && level > mCriticalLevel && mShowPercent) {
mTextPaint.setColor(getColorForLevel(level));
mTextPaint.setTextSize(height *
(SINGLE_DIGIT_PERCENT ? 0.75f
@@ -480,7 +480,7 @@
mShapePath.op(mClipPath, Path.Op.INTERSECT);
c.drawPath(mShapePath, mBatteryPaint);
- if (!mPluggedIn) {
+ if (!mPluggedIn && !mPowerSaveEnabled) {
if (level <= mCriticalLevel) {
// draw the warning text
final float x = mWidth * 0.5f;
diff --git a/packages/SystemUI/src/com/android/systemui/Interpolators.java b/packages/SystemUI/src/com/android/systemui/Interpolators.java
index 5e33a9f..17f4dab 100644
--- a/packages/SystemUI/src/com/android/systemui/Interpolators.java
+++ b/packages/SystemUI/src/com/android/systemui/Interpolators.java
@@ -17,6 +17,7 @@
package com.android.systemui;
import android.view.animation.AccelerateDecelerateInterpolator;
+import android.view.animation.AccelerateInterpolator;
import android.view.animation.DecelerateInterpolator;
import android.view.animation.Interpolator;
import android.view.animation.LinearInterpolator;
@@ -32,6 +33,7 @@
public static final Interpolator ALPHA_IN = new PathInterpolator(0.4f, 0f, 1f, 1f);
public static final Interpolator ALPHA_OUT = new PathInterpolator(0f, 0f, 0.8f, 1f);
public static final Interpolator LINEAR = new LinearInterpolator();
+ public static final Interpolator ACCELERATE = new AccelerateInterpolator();
public static final Interpolator ACCELERATE_DECELERATE = new AccelerateDecelerateInterpolator();
public static final Interpolator DECELERATE_QUINT = new DecelerateInterpolator(2.5f);
diff --git a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
index 8f79bda..c0a565db 100644
--- a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
@@ -325,10 +325,11 @@
/**
* @param view The view to be dismissed
* @param velocity The desired pixels/second speed at which the view should move
+ * @param useAccelerateInterpolator Should an accelerating Interpolator be used
*/
- public void dismissChild(final View view, float velocity) {
+ public void dismissChild(final View view, float velocity, boolean useAccelerateInterpolator) {
dismissChild(view, velocity, null /* endAction */, 0 /* delay */,
- velocity == 0 /* useAccelerateInterpolator */, 0 /* fixedDuration */);
+ useAccelerateInterpolator, 0 /* fixedDuration */);
}
/**
@@ -569,7 +570,8 @@
if (!handleUpEvent(ev, mCurrView, velocity, getTranslation(mCurrView))) {
if (isDismissGesture(ev)) {
// flingadingy
- dismissChild(mCurrView, swipedFastEnough() ? velocity : 0f);
+ dismissChild(mCurrView, velocity,
+ !swipedFastEnough() /* useAccelerateInterpolator */);
} else {
// snappity
mCallback.onDragCancelled(mCurrView);
@@ -615,11 +617,9 @@
protected boolean swipedFastEnough() {
float velocity = getVelocity(mVelocityTracker);
- float perpendicularVelocity = getPerpendicularVelocity(mVelocityTracker);
float translation = getTranslation(mCurrView);
- boolean ret = (Math.abs(velocity) > getEscapeVelocity()) &&
- (Math.abs(velocity) > Math.abs(perpendicularVelocity)) &&
- (velocity > 0) == (translation > 0);
+ boolean ret = (Math.abs(velocity) > getEscapeVelocity())
+ && (velocity > 0) == (translation > 0);
return ret;
}
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
index 0d75fdd..53c2233 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
@@ -27,9 +27,25 @@
import com.android.systemui.statusbar.phone.KeyguardBouncer;
import com.android.systemui.statusbar.phone.NotificationIconAreaController;
import com.android.systemui.statusbar.phone.PhoneStatusBar;
+import com.android.systemui.statusbar.phone.QSTileHost;
import com.android.systemui.statusbar.phone.ScrimController;
+import com.android.systemui.statusbar.phone.StatusBarIconController;
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
import com.android.systemui.statusbar.phone.StatusBarWindowManager;
+import com.android.systemui.statusbar.policy.BatteryController;
+import com.android.systemui.statusbar.policy.BluetoothController;
+import com.android.systemui.statusbar.policy.CastController;
+import com.android.systemui.statusbar.policy.FlashlightController;
+import com.android.systemui.statusbar.policy.HotspotController;
+import com.android.systemui.statusbar.policy.KeyguardMonitor;
+import com.android.systemui.statusbar.policy.LocationController;
+import com.android.systemui.statusbar.policy.NetworkController;
+import com.android.systemui.statusbar.policy.NextAlarmController;
+import com.android.systemui.statusbar.policy.RotationLockController;
+import com.android.systemui.statusbar.policy.SecurityController;
+import com.android.systemui.statusbar.policy.UserInfoController;
+import com.android.systemui.statusbar.policy.UserSwitcherController;
+import com.android.systemui.statusbar.policy.ZenModeController;
/**
* Class factory to provide customizable SystemUI components.
@@ -82,6 +98,20 @@
return new NotificationIconAreaController(context, phoneStatusBar);
}
+ public QSTileHost createQSTileHost(Context context, PhoneStatusBar statusBar,
+ BluetoothController bluetooth, LocationController location,
+ RotationLockController rotation, NetworkController network,
+ ZenModeController zen, HotspotController hotspot,
+ CastController cast, FlashlightController flashlight,
+ UserSwitcherController userSwitcher, UserInfoController userInfo,
+ KeyguardMonitor keyguard, SecurityController security,
+ BatteryController battery, StatusBarIconController iconController,
+ NextAlarmController nextAlarmController) {
+ return new QSTileHost(context, statusBar, bluetooth, location, rotation, network, zen,
+ hotspot, cast, flashlight, userSwitcher, userInfo, keyguard, security, battery,
+ iconController, nextAlarmController);
+ }
+
public <T> T createInstance(Class<T> classType) {
return null;
}
diff --git a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
index 522d533..109a456 100644
--- a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
+++ b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
@@ -183,14 +183,16 @@
return;
}
+ boolean isPowerSaver = mPowerManager.isPowerSaveMode();
if (!plugged
+ && !isPowerSaver
&& (bucket < oldBucket || oldPlugged)
&& mBatteryStatus != BatteryManager.BATTERY_STATUS_UNKNOWN
&& bucket < 0) {
// only play SFX when the dialog comes up or the bucket changes
final boolean playSound = bucket != oldBucket || oldPlugged;
mWarnings.showLowBatteryWarning(playSound);
- } else if (plugged || (bucket > oldBucket && bucket > 0)) {
+ } else if (isPowerSaver || plugged || (bucket > oldBucket && bucket > 0)) {
mWarnings.dismissLowBatteryWarning();
} else {
mWarnings.updateLowBatteryWarning();
diff --git a/packages/SystemUI/src/com/android/systemui/qs/PageIndicator.java b/packages/SystemUI/src/com/android/systemui/qs/PageIndicator.java
index 1200266..ba07bf4 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/PageIndicator.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/PageIndicator.java
@@ -1,86 +1,219 @@
package com.android.systemui.qs;
import android.content.Context;
-import android.graphics.Canvas;
-import android.graphics.Paint;
+import android.graphics.drawable.AnimatedVectorDrawable;
import android.util.AttributeSet;
-import android.view.Gravity;
+import android.util.Log;
import android.view.View;
-import android.widget.LinearLayout;
-
+import android.view.ViewGroup;
+import android.widget.ImageView;
import com.android.systemui.R;
-public class PageIndicator extends LinearLayout {
+import java.util.ArrayList;
- private final int mPageIndicatorSize;
+public class PageIndicator extends ViewGroup {
+
+ private static final String TAG = "PageIndicator";
+ private static final boolean DEBUG = false;
+
+ private static final long ANIMATION_DURATION = 250;
+
+ // The size of a single dot in relation to the whole animation.
+ private static final float SINGLE_SCALE = .4f;
+
+ private static final float MINOR_ALPHA = .3f;
+
+ private final ArrayList<Integer> mQueuedPositions = new ArrayList<>();
+
+ private final int mPageIndicatorWidth;
+ private final int mPageIndicatorHeight;
+ private final int mPageDotWidth;
+
+ private int mPosition = -1;
+ private boolean mAnimating;
public PageIndicator(Context context, AttributeSet attrs) {
super(context, attrs);
- setGravity(Gravity.CENTER);
- mPageIndicatorSize =
- (int) mContext.getResources().getDimension(R.dimen.qs_page_indicator_size);
+ mPageIndicatorWidth =
+ (int) mContext.getResources().getDimension(R.dimen.qs_page_indicator_width);
+ mPageIndicatorHeight =
+ (int) mContext.getResources().getDimension(R.dimen.qs_page_indicator_height);
+ mPageDotWidth = (int) (mPageIndicatorWidth * SINGLE_SCALE);
}
public void setNumPages(int numPages) {
+ setVisibility(numPages > 1 ? View.VISIBLE : View.INVISIBLE);
+ if (mAnimating) {
+ Log.w(TAG, "setNumPages during animation");
+ }
while (numPages < getChildCount()) {
removeViewAt(getChildCount() - 1);
}
while (numPages > getChildCount()) {
- SinglePageIndicator v = new SinglePageIndicator(mContext);
- v.setAmount(0);
- addView(v, new LayoutParams(mPageIndicatorSize, mPageIndicatorSize));
+ ImageView v = new ImageView(mContext);
+ v.setImageResource(R.drawable.minor_a_b);
+ addView(v, new LayoutParams(mPageIndicatorWidth, mPageIndicatorHeight));
}
+ // Refresh state.
+ setIndex(mPosition >> 1);
}
public void setLocation(float location) {
int index = (int) location;
- location -= index;
+ int position = index << 1 | ((location != index) ? 1 : 0);
+ if (DEBUG) Log.d(TAG, "setLocation " + location + " " + index + " " + position);
+ int lastPosition = mPosition;
+ if (mQueuedPositions.size() != 0) {
+ lastPosition = mQueuedPositions.get(mQueuedPositions.size() - 1);
+ }
+ if (position == lastPosition) return;
+ if (mAnimating) {
+ if (DEBUG) Log.d(TAG, "Queueing transition to " + Integer.toHexString(position));
+ mQueuedPositions.add(position);
+ return;
+ }
+
+ setPosition(position);
+ }
+
+ private void setPosition(int position) {
+ if (isVisibleToUser() && Math.abs(mPosition - position) == 1) {
+ animate(mPosition, position);
+ } else {
+ if (DEBUG) Log.d(TAG, "Skipping animation " + isVisibleToUser() + " " + mPosition
+ + " " + position);
+ setIndex(position >> 1);
+ }
+ mPosition = position;
+ }
+
+ private void setIndex(int index) {
final int N = getChildCount();
for (int i = 0; i < N; i++) {
- float amount = 0;
- if (i == index) {
- amount = 1 - location;
- } else if (i == index + 1) {
- amount = location;
+ ImageView v = (ImageView) getChildAt(i);
+ // Clear out any animation positioning.
+ v.setTranslationX(0);
+ v.setImageResource(R.drawable.major_a_b);
+ v.setAlpha(getAlpha(i == index));
+ }
+ }
+
+ private void animate(int from, int to) {
+ if (DEBUG) Log.d(TAG, "Animating from " + Integer.toHexString(from) + " to "
+ + Integer.toHexString(to));
+ int fromIndex = from >> 1;
+ int toIndex = to >> 1;
+
+ // Set the position of everything, then we will manually control the two views involved
+ // in the animation.
+ setIndex(fromIndex);
+
+ boolean fromTransition = (from & 1) != 0;
+ boolean isAState = fromTransition ? from > to : from < to;
+ int firstIndex = Math.min(fromIndex, toIndex);
+ int secondIndex = Math.max(fromIndex, toIndex);
+ if (secondIndex == firstIndex) {
+ secondIndex++;
+ }
+ ImageView first = (ImageView) getChildAt(firstIndex);
+ ImageView second = (ImageView) getChildAt(secondIndex);
+ // Lay the two views on top of each other.
+ second.setTranslationX(first.getX() - second.getX());
+
+ playAnimation(first, getTransition(fromTransition, isAState, false));
+ first.setAlpha(getAlpha(false));
+
+ playAnimation(second, getTransition(fromTransition, isAState, true));
+ second.setAlpha(getAlpha(true));
+
+ mAnimating = true;
+ }
+
+ private float getAlpha(boolean isMajor) {
+ return isMajor ? 1 : MINOR_ALPHA;
+ }
+
+ private void playAnimation(ImageView imageView, int res) {
+ final AnimatedVectorDrawable avd = (AnimatedVectorDrawable) getContext().getDrawable(res);
+ imageView.setImageDrawable(avd);
+ avd.forceAnimationOnUI();
+ avd.start();
+ // TODO: Figure out how to user an AVD animation callback instead, which doesn't
+ // seem to be working right now...
+ postDelayed(mAnimationDone, ANIMATION_DURATION);
+ }
+
+ private int getTransition(boolean fromB, boolean isMajorAState, boolean isMajor) {
+ if (isMajor) {
+ if (fromB) {
+ if (isMajorAState) {
+ return R.drawable.major_b_a_animation;
+ } else {
+ return R.drawable.major_b_c_animation;
+ }
+ } else {
+ if (isMajorAState) {
+ return R.drawable.major_a_b_animation;
+ } else {
+ return R.drawable.major_c_b_animation;
+ }
}
- ((SinglePageIndicator) getChildAt(i)).setAmount(amount);
+ } else {
+ if (fromB) {
+ if (isMajorAState) {
+ return R.drawable.minor_b_c_animation;
+ } else {
+ return R.drawable.minor_b_a_animation;
+ }
+ } else {
+ if (isMajorAState) {
+ return R.drawable.minor_c_b_animation;
+ } else {
+ return R.drawable.minor_a_b_animation;
+ }
+ }
}
}
- // This could be done with a circle drawable and an ImageView, but this seems
- // easier for now.
- public static class SinglePageIndicator extends View {
- private static final int MIN_ALPHA = 0x4d;
- private static final int MAX_ALPHA = 0xff;
-
- private static final float MIN_SIZE = .55f;
- private static final float MAX_SIZE = .7f;
-
- private final Paint mPaint;
- private float mSize;
-
- public SinglePageIndicator(Context context) {
- super(context);
- mPaint = new Paint();
- mPaint.setColor(0xffffffff);
- mPaint.setAlpha(MAX_ALPHA);
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ final int N = getChildCount();
+ if (N == 0) {
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+ return;
}
-
- public void setAmount(float amount) {
- mSize = amount * (MAX_SIZE - MIN_SIZE) + MIN_SIZE;
- int alpha = (int) (amount * (MAX_ALPHA - MIN_ALPHA)) + MIN_ALPHA;
- mPaint.setAlpha(alpha);
- postInvalidate();
+ final int widthChildSpec = MeasureSpec.makeMeasureSpec(mPageIndicatorWidth,
+ MeasureSpec.EXACTLY);
+ final int heightChildSpec = MeasureSpec.makeMeasureSpec(mPageIndicatorHeight,
+ MeasureSpec.EXACTLY);
+ for (int i = 0; i < N; i++) {
+ getChildAt(i).measure(widthChildSpec, heightChildSpec);
}
+ int width = (mPageIndicatorWidth - mPageDotWidth) * N + mPageDotWidth;
+ setMeasuredDimension(width, mPageIndicatorHeight);
+ }
+ @Override
+ protected void onLayout(boolean changed, int l, int t, int r, int b) {
+ final int N = getChildCount();
+ if (N == 0) {
+ return;
+ }
+ for (int i = 0; i < N; i++) {
+ int left = (mPageIndicatorWidth - mPageDotWidth) * i;
+ getChildAt(i).layout(left, 0, mPageIndicatorWidth + left, mPageIndicatorHeight);
+ }
+ }
+
+ private final Runnable mAnimationDone = new Runnable() {
@Override
- public void draw(Canvas canvas) {
- int minDimen = Math.min(getWidth(), getHeight()) / 2;
- float radius = mSize * minDimen;
- float x = getWidth() / 2f;
- float y = getHeight() / 2f;
- canvas.drawCircle(x, y, radius, mPaint);
+ public void run() {
+ if (DEBUG) Log.d(TAG, "onAnimationEnd - queued: " + mQueuedPositions.size());
+ mAnimating = false;
+ if (mQueuedPositions.size() != 0) {
+ setPosition(mQueuedPositions.remove(0));
+ }
}
- }
+ };
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
index 24b45cc..115c9d0 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
@@ -1,13 +1,13 @@
package com.android.systemui.qs;
import android.content.Context;
+import android.support.v4.view.PagerAdapter;
+import android.support.v4.view.ViewPager;
import android.util.AttributeSet;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
-import com.android.internal.widget.PagerAdapter;
-import com.android.internal.widget.ViewPager;
import com.android.systemui.R;
import com.android.systemui.qs.QSPanel.QSTileLayout;
import com.android.systemui.qs.QSPanel.TileRecord;
@@ -36,9 +36,9 @@
@Override
public void onPageSelected(int position) {
if (mPageIndicator == null) return;
- mPageIndicator.setLocation(position);
if (mPageListener != null) {
- mPageListener.onPageChanged(position == 0);
+ mPageListener.onPageChanged(isLayoutRtl() ? position == mPages.size() - 1
+ : position == 0);
}
}
@@ -48,7 +48,8 @@
if (mPageIndicator == null) return;
mPageIndicator.setLocation(position + positionOffset);
if (mPageListener != null) {
- mPageListener.onPageChanged(position == 0 && positionOffsetPixels == 0);
+ mPageListener.onPageChanged(positionOffsetPixels == 0 &&
+ (isLayoutRtl() ? position == mPages.size() - 1 : position == 0));
}
}
@@ -60,6 +61,21 @@
}
@Override
+ public void onRtlPropertiesChanged(int layoutDirection) {
+ super.onRtlPropertiesChanged(layoutDirection);
+ setAdapter(mAdapter);
+ setCurrentItem(0, false);
+ }
+
+ @Override
+ public void setCurrentItem(int item, boolean smoothScroll) {
+ if (isLayoutRtl()) {
+ item = mPages.size() - 1 - item;
+ }
+ super.setCurrentItem(item, smoothScroll);
+ }
+
+ @Override
public boolean hasOverlappingRendering() {
return false;
}
@@ -129,6 +145,7 @@
mNumPages = index + 1;
mPageIndicator.setNumPages(mNumPages);
mAdapter.notifyDataSetChanged();
+ setCurrentItem(0, false);
}
}
@@ -207,6 +224,9 @@
public Object instantiateItem(ViewGroup container, int position) {
if (DEBUG) Log.d(TAG, "Instantiating " + position);
+ if (isLayoutRtl()) {
+ position = mPages.size() - 1 - position;
+ }
ViewGroup view = mPages.get(position);
container.addView(view);
return view;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java b/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
index 815c679..de8eec4 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
@@ -41,7 +41,7 @@
private static final String MOVE_FULL_ROWS = "sysui_qs_move_whole_rows";
public static final float EXPANDED_TILE_DELAY = .7f;
- private static final float LAST_ROW_EXPANDED_DELAY = .84f;
+ private static final float LAST_ROW_EXPANDED_DELAY = .86f;
private final ArrayList<View> mAllViews = new ArrayList<>();
private final ArrayList<View> mTopFiveQs = new ArrayList<>();
@@ -64,6 +64,7 @@
private boolean mAllowFancy;
private boolean mFullRows;
private int mNumQuickTiles;
+ private float mLastPosition;
public QSAnimator(QSContainer container, QuickQSPanel quickPanel, QSPanel panel) {
mQsContainer = container;
@@ -80,6 +81,10 @@
}
}
+ public void onRtlChanged() {
+ updateAnimators();
+ }
+
public void setOnKeyguard(boolean onKeyguard) {
mOnKeyguard = onKeyguard;
if (mOnKeyguard) {
@@ -113,7 +118,7 @@
} else if (MOVE_FULL_ROWS.equals(key)) {
mFullRows = newValue == null || Integer.parseInt(newValue) != 0;
} else if (QuickQSPanel.NUM_QUICK_TILES.equals(key)) {
- mNumQuickTiles = QuickQSPanel.getNumQuickTiles(mQsContainer.getContext());
+ mNumQuickTiles = mQuickQsPanel.getNumQuickTiles(mQsContainer.getContext());
clearAnimationState();
}
updateAnimators();
@@ -139,7 +144,9 @@
int count = 0;
int[] loc1 = new int[2];
int[] loc2 = new int[2];
+ int lastXDiff = 0;
int lastYDiff = 0;
+ int lastX = 0;
clearAnimationState();
mAllViews.clear();
@@ -155,10 +162,12 @@
// Quick tiles.
QSTileBaseView quickTileView = mQuickQsPanel.getTileView(tile);
+ lastX = loc1[0];
getRelativePosition(loc1, quickTileView.getIcon(), mQsContainer);
getRelativePosition(loc2, tileIcon, mQsContainer);
final int xDiff = loc2[0] - loc1[0];
final int yDiff = loc2[1] - loc1[1];
+ lastXDiff = loc1[0] - lastX;
lastYDiff = yDiff;
// Move the quick tile right from its location to the new one.
translationXBuilder.addFloat(quickTileView, "translationX", 0, xDiff);
@@ -177,9 +186,20 @@
mAllViews.add(tileIcon);
mAllViews.add(quickTileView);
} else if (mFullRows && isIconInAnimatedRow(count)) {
+ // TODO: Refactor some of this, it shares a lot with the above block.
+ // Move the last tile position over by the last difference between quick tiles.
+ // This makes the extra icons seems as if they are coming from positions in the
+ // quick panel.
+ loc1[0] += lastXDiff;
+ getRelativePosition(loc2, tileIcon, mQsContainer);
+ final int xDiff = loc2[0] - loc1[0];
+ final int yDiff = loc2[1] - loc1[1];
+
firstPageBuilder.addFloat(tileView, "translationY", mQsPanel.getHeight(), 0);
- translationYBuilder.addFloat(label, "translationY", -lastYDiff, 0);
- translationYBuilder.addFloat(tileIcon, "translationY", -lastYDiff, 0);
+ translationXBuilder.addFloat(tileView, "translationX", -xDiff, 0);
+ translationYBuilder.addFloat(label, "translationY", -yDiff, 0);
+ translationYBuilder.addFloat(tileIcon, "translationY", -yDiff, 0);
+
mAllViews.add(tileIcon);
} else {
lastRowBuilder.addFloat(tileView, "alpha", 0, 1);
@@ -231,7 +251,7 @@
private void getRelativePositionInt(int[] loc1, View view, View parent) {
if(view == parent || view == null) return;
- loc1[0] += view.getLeft();
+ loc1[0] += view.getX();
loc1[1] += view.getTop();
getRelativePositionInt(loc1, (View) view.getParent(), parent);
}
@@ -241,6 +261,7 @@
if (mOnKeyguard) {
return;
}
+ mLastPosition = position;
if (mOnFirstPage && mAllowFancy) {
mQuickQsPanel.setAlpha(1);
mFirstPageAnimator.setPosition(position);
@@ -281,7 +302,7 @@
private void clearAnimationState() {
final int N = mAllViews.size();
mQuickQsPanel.setAlpha(0);
- mQuickQsPanel.setVisibility(View.INVISIBLE);
+ mQuickQsPanel.setVisibility(View.VISIBLE);
for (int i = 0; i < N; i++) {
View v = mAllViews.get(i);
v.setAlpha(1);
@@ -297,7 +318,7 @@
@Override
public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft,
int oldTop, int oldRight, int oldBottom) {
- updateAnimators();
+ mQsPanel.post(mUpdateAnimators);
}
@Override
@@ -319,6 +340,7 @@
@Override
public void run() {
updateAnimators();
+ setPosition(mLastPosition);
}
};
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSContainer.java b/packages/SystemUI/src/com/android/systemui/qs/QSContainer.java
index 5b05e84..5d06aeb 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSContainer.java
@@ -20,6 +20,7 @@
import android.animation.AnimatorListenerAdapter;
import android.content.Context;
import android.graphics.Point;
+import android.graphics.Rect;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
@@ -43,6 +44,7 @@
private static final boolean DEBUG = false;
private final Point mSizePoint = new Point();
+ private final Rect mQsBounds = new Rect();
private int mHeightOverride = -1;
private QSPanel mQSPanel;
@@ -76,6 +78,12 @@
mQSCustomizer.setQsContainer(this);
}
+ @Override
+ public void onRtlPropertiesChanged(int layoutDirection) {
+ super.onRtlPropertiesChanged(layoutDirection);
+ mQSAnimator.onRtlChanged();
+ }
+
public void setHost(QSTileHost qsh) {
mQSPanel.setHost(qsh, mQSCustomizer);
mHeader.setQSPanel(mQSPanel);
@@ -140,6 +148,8 @@
public void notifyCustomizeChanged() {
// The customize state changed, so our height changed.
updateBottom();
+ mQSPanel.setVisibility(!mQSCustomizer.isCustomizing() ? View.VISIBLE : View.INVISIBLE);
+ mHeader.setVisibility(!mQSCustomizer.isCustomizing() ? View.VISIBLE : View.INVISIBLE);
// Let the panel know the position changed and it needs to update where notifications
// and whatnot are.
mPanelView.onQsHeightChanged();
@@ -224,6 +234,12 @@
mQSDetail.setFullyExpanded(expansion == 1);
mQSAnimator.setPosition(expansion);
updateBottom();
+
+ // Set bounds on the QS panel so it doesn't run over the header.
+ mQsBounds.top = (int) (mQSPanel.getHeight() * (1 - expansion));
+ mQsBounds.right = mQSPanel.getWidth();
+ mQsBounds.bottom = mQSPanel.getHeight();
+ mQSPanel.setClipBounds(mQsBounds);
}
public void animateHeaderSlidingIn(long delay) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
index 899b0ef..a05818a 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
@@ -119,12 +119,18 @@
protected void onAttachedToWindow() {
super.onAttachedToWindow();
TunerService.get(mContext).addTunable(this, QS_SHOW_BRIGHTNESS);
+ if (mHost != null) {
+ setTiles(mHost.getTiles());
+ }
}
@Override
protected void onDetachedFromWindow() {
TunerService.get(mContext).removeTunable(this);
mHost.removeCallback(this);
+ for (TileRecord record : mRecords) {
+ record.tile.removeCallbacks();
+ }
super.onDetachedFromWindow();
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTile.java b/packages/SystemUI/src/com/android/systemui/qs/QSTile.java
index 42e98aa..3e32905 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSTile.java
@@ -29,6 +29,8 @@
import android.view.View;
import android.view.ViewGroup;
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.MetricsProto.MetricsEvent;
import com.android.settingslib.RestrictedLockUtils;
import com.android.systemui.qs.QSTile.State;
import com.android.systemui.qs.external.TileServices;
@@ -212,6 +214,7 @@
}
protected void handleLongClick() {
+ MetricsLogger.action(mContext, MetricsEvent.ACTION_QS_LONG_PRESS, getTileSpec());
mHost.startActivityDismissingKeyguard(getLongClickIntent());
}
@@ -294,6 +297,8 @@
}
}
+ public abstract CharSequence getTileLabel();
+
protected final class H extends Handler {
private static final int ADD_CALLBACK = 1;
private static final int CLICK = 2;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTileView.java b/packages/SystemUI/src/com/android/systemui/qs/QSTileView.java
index 98a1c23..57a1a4a 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSTileView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSTileView.java
@@ -37,7 +37,7 @@
private final int mTileSpacingPx;
private int mTilePaddingTopPx;
- private TextView mLabel;
+ protected TextView mLabel;
private ImageView mPadLock;
public QSTileView(Context context, QSIconView icon) {
@@ -81,7 +81,7 @@
FontSizeUtils.updateFontSize(mLabel, R.dimen.qs_tile_text_size);
}
- private void createLabel() {
+ protected void createLabel() {
final Resources res = mContext.getResources();
View view = LayoutInflater.from(mContext).inflate(R.layout.qs_tile_label, null);
mLabel = (TextView) view.findViewById(R.id.tile_label);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
index ab90179..2ef3672 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
@@ -143,7 +143,7 @@
}
};
- public static int getNumQuickTiles(Context context) {
+ public int getNumQuickTiles(Context context) {
return TunerService.get(context).getValue(NUM_QUICK_TILES, 5);
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/CustomizeTileView.java b/packages/SystemUI/src/com/android/systemui/qs/customize/CustomizeTileView.java
new file mode 100644
index 0000000..e512f93
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/CustomizeTileView.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+package com.android.systemui.qs.customize;
+
+import android.content.Context;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.TextView;
+import com.android.systemui.R;
+import com.android.systemui.qs.QSIconView;
+import com.android.systemui.qs.QSTileView;
+import libcore.util.Objects;
+
+public class CustomizeTileView extends QSTileView {
+
+ private TextView mAppLabel;
+
+ public CustomizeTileView(Context context, QSIconView icon) {
+ super(context, icon);
+ }
+
+ @Override
+ protected void createLabel() {
+ super.createLabel();
+ View view = LayoutInflater.from(mContext).inflate(R.layout.qs_tile_label, null);
+ mAppLabel = (TextView) view.findViewById(R.id.tile_label);
+ mAppLabel.setAlpha(.6f);
+ mAppLabel.setSingleLine(true);
+ addView(view);
+ }
+
+ public void setShowAppLabel(boolean showAppLabel) {
+ mAppLabel.setVisibility(showAppLabel ? View.VISIBLE : View.GONE);
+ mLabel.setSingleLine(showAppLabel);
+ }
+
+ public void setAppLabel(CharSequence label) {
+ if (!Objects.equal(label, mAppLabel.getText())) {
+ mAppLabel.setText(label);
+ }
+ }
+
+ public TextView getAppLabel() {
+ return mAppLabel;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java b/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
index aeca840..716185f 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
@@ -32,6 +32,8 @@
import android.widget.LinearLayout;
import android.widget.Toolbar;
import android.widget.Toolbar.OnMenuItemClickListener;
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.MetricsProto;
import com.android.systemui.R;
import com.android.systemui.qs.QSContainer;
import com.android.systemui.qs.QSDetailClipper;
@@ -116,23 +118,27 @@
public void show(int x, int y) {
if (!isShown) {
+ MetricsLogger.visible(getContext(), MetricsProto.MetricsEvent.QS_EDIT);
isShown = true;
setTileSpecs();
setVisibility(View.VISIBLE);
mClipper.animateCircularClip(x, y, true, mExpandAnimationListener);
new TileQueryHelper(mContext, mHost).setListener(mTileAdapter);
mNotifQsContainer.setCustomizerAnimating(true);
+ mNotifQsContainer.setCustomizerShowing(true);
}
}
public void hide(int x, int y) {
if (isShown) {
+ MetricsLogger.hidden(getContext(), MetricsProto.MetricsEvent.QS_EDIT);
isShown = false;
mToolbar.dismissPopupMenus();
setCustomizing(false);
save();
mClipper.animateCircularClip(x, y, false, mCollapseAnimationListener);
mNotifQsContainer.setCustomizerAnimating(true);
+ mNotifQsContainer.setCustomizerShowing(false);
}
}
@@ -149,6 +155,7 @@
public boolean onMenuItemClick(MenuItem item) {
switch (item.getItemId()) {
case MENU_RESET:
+ MetricsLogger.action(getContext(), MetricsProto.MetricsEvent.ACTION_QS_EDIT_RESET);
reset();
break;
}
@@ -170,6 +177,7 @@
specs.add(tile.getTileSpec());
}
mTileAdapter.setTileSpecs(specs);
+ mRecyclerView.setAdapter(mTileAdapter);
}
private void save() {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java b/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
index 03c2a0b..2ba4044 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
@@ -14,7 +14,11 @@
package com.android.systemui.qs.customize;
+import android.app.AlertDialog;
+import android.app.AlertDialog.Builder;
+import android.content.ComponentName;
import android.content.Context;
+import android.content.DialogInterface;
import android.graphics.Canvas;
import android.graphics.drawable.ColorDrawable;
import android.os.Handler;
@@ -27,16 +31,22 @@
import android.support.v7.widget.helper.ItemTouchHelper;
import android.view.LayoutInflater;
import android.view.View;
+import android.view.View.OnClickListener;
+import android.view.View.OnLayoutChangeListener;
import android.view.ViewGroup;
+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;
import com.android.systemui.qs.QSIconView;
-import com.android.systemui.qs.QSTileView;
import com.android.systemui.qs.customize.TileAdapter.Holder;
import com.android.systemui.qs.customize.TileQueryHelper.TileInfo;
import com.android.systemui.qs.customize.TileQueryHelper.TileStateListener;
+import com.android.systemui.qs.external.CustomTile;
import com.android.systemui.statusbar.phone.QSTileHost;
+import com.android.systemui.statusbar.phone.SystemUIDialog;
import java.util.ArrayList;
import java.util.List;
@@ -49,28 +59,40 @@
private static final int TYPE_TILE = 0;
private static final int TYPE_EDIT = 1;
+ private static final int TYPE_ACCESSIBLE_DROP = 2;
+ private static final int TYPE_DIVIDER = 4;
+
+ private static final long EDIT_ID = 10000;
+ private static final long DIVIDER_ID = 20000;
private final Context mContext;
private final Handler mHandler = new Handler();
private final List<TileInfo> mTiles = new ArrayList<>();
private final ItemTouchHelper mItemTouchHelper;
- private int mDividerIndex;
+ private final AccessibilityManager mAccessibilityManager;
+ private int mEditIndex;
+ private int mTileDividerIndex;
+ private boolean mNeedsFocus;
private List<String> mCurrentSpecs;
private List<TileInfo> mOtherTiles;
private List<TileInfo> mAllTiles;
private Holder mCurrentDrag;
+ private boolean mAccessibilityMoving;
+ private int mAccessibilityFromIndex;
public TileAdapter(Context context) {
mContext = context;
+ mAccessibilityManager = context.getSystemService(AccessibilityManager.class);
mItemTouchHelper = new ItemTouchHelper(mCallbacks);
setHasStableIds(true);
}
@Override
public long getItemId(int position) {
- return mTiles.get(position) != null ? mAllTiles.indexOf(mTiles.get(position)) : -1;
+ return mTiles.get(position) != null ? mAllTiles.indexOf(mTiles.get(position))
+ : position == mEditIndex ? EDIT_ID : DIVIDER_ID;
}
public ItemTouchHelper getItemTouchHelper() {
@@ -114,8 +136,19 @@
}
}
mTiles.add(null);
+ for (int i = 0; i < mOtherTiles.size(); i++) {
+ final TileInfo tile = mOtherTiles.get(i);
+ if (tile.isSystem) {
+ mOtherTiles.remove(i--);
+ mTiles.add(tile);
+ }
+ }
+ if (mOtherTiles.size() != 0) {
+ mTileDividerIndex = mTiles.size();
+ mTiles.add(null);
+ }
mTiles.addAll(mOtherTiles);
- mDividerIndex = mTiles.indexOf(null);
+ mEditIndex = mTiles.indexOf(null);
notifyDataSetChanged();
}
@@ -130,6 +163,12 @@
@Override
public int getItemViewType(int position) {
+ if (mAccessibilityMoving && position == mEditIndex - 1) {
+ return TYPE_ACCESSIBLE_DROP;
+ }
+ if (position == mTileDividerIndex) {
+ return TYPE_DIVIDER;
+ }
if (mTiles.get(position) == null) {
return TYPE_EDIT;
}
@@ -140,12 +179,15 @@
public Holder onCreateViewHolder(ViewGroup parent, int viewType) {
final Context context = parent.getContext();
LayoutInflater inflater = LayoutInflater.from(context);
- if (viewType == 1) {
+ if (viewType == TYPE_DIVIDER) {
+ return new Holder(inflater.inflate(R.layout.qs_customize_tile_divider, parent, false));
+ }
+ if (viewType == TYPE_EDIT) {
return new Holder(inflater.inflate(R.layout.qs_customize_divider, parent, false));
}
FrameLayout frame = (FrameLayout) inflater.inflate(R.layout.qs_customize_tile_frame, parent,
false);
- frame.addView(new QSTileView(context, new QSIconView(context)));
+ frame.addView(new CustomizeTileView(context, new QSIconView(context)));
return new Holder(frame);
}
@@ -155,29 +197,222 @@
}
@Override
- public void onBindViewHolder(final Holder holder, int position) {
+ public void onBindViewHolder(final Holder holder, final int position) {
+ if (holder.getItemViewType() == TYPE_DIVIDER) {
+ return;
+ }
if (holder.getItemViewType() == TYPE_EDIT) {
((TextView) holder.itemView.findViewById(android.R.id.title)).setText(
mCurrentDrag != null ? R.string.drag_to_remove_tiles
: R.string.drag_to_add_tiles);
return;
}
+ if (holder.getItemViewType() == TYPE_ACCESSIBLE_DROP) {
+ holder.mTileView.setClickable(true);
+ holder.mTileView.setFocusable(true);
+ holder.mTileView.setFocusableInTouchMode(true);
+ holder.mTileView.setVisibility(View.VISIBLE);
+ holder.mTileView.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES);
+ holder.mTileView.setContentDescription(mContext.getString(
+ R.string.accessibility_qs_edit_position_label, position + 1));
+ holder.mTileView.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ selectPosition(position, v);
+ }
+ });
+ if (mNeedsFocus) {
+ // Wait for this to get laid out then set its focus.
+ holder.mTileView.addOnLayoutChangeListener(new OnLayoutChangeListener() {
+ @Override
+ public void onLayoutChange(View v, int left, int top, int right, int bottom,
+ int oldLeft, int oldTop, int oldRight, int oldBottom) {
+ holder.mTileView.removeOnLayoutChangeListener(this);
+ holder.mTileView.requestFocus();
+ }
+ });
+ mNeedsFocus = false;
+ }
+ return;
+ }
TileInfo info = mTiles.get(position);
+
+ if (position > mEditIndex) {
+ info.state.contentDescription = mContext.getString(
+ R.string.accessibility_qs_edit_add_tile_label, info.state.label);
+ } else if (mAccessibilityMoving) {
+ info.state.contentDescription = mContext.getString(
+ R.string.accessibility_qs_edit_position_label, position + 1);
+ } else {
+ info.state.contentDescription = mContext.getString(
+ R.string.accessibility_qs_edit_tile_label, position + 1, info.state.label);
+ }
holder.mTileView.onStateChanged(info.state);
+ holder.mTileView.setAppLabel(info.appLabel);
+ holder.mTileView.setShowAppLabel(position > mTileDividerIndex);
+
+ if (mAccessibilityManager.isTouchExplorationEnabled()) {
+ final boolean selectable = !mAccessibilityMoving || position < mEditIndex;
+ holder.mTileView.setClickable(selectable);
+ holder.mTileView.setFocusable(selectable);
+ holder.mTileView.setImportantForAccessibility(selectable
+ ? View.IMPORTANT_FOR_ACCESSIBILITY_YES
+ : View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS);
+ if (selectable) {
+ holder.mTileView.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ if (mAccessibilityMoving) {
+ selectPosition(position, v);
+ } else {
+ if (position < mEditIndex) {
+ showAccessibilityDialog(position, v);
+ } else {
+ startAccessibleDrag(position);
+ }
+ }
+ }
+ });
+ }
+ }
+ }
+
+ private void selectPosition(int position, View v) {
+ // Remove the placeholder.
+ mTiles.remove(mEditIndex--);
+ mAccessibilityMoving = false;
+ move(mAccessibilityFromIndex, position, v);
+ notifyDataSetChanged();
+ }
+
+ private void showAccessibilityDialog(final int position, final View v) {
+ 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),
+ };
+ AlertDialog dialog = new Builder(mContext)
+ .setItems(options, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ if (which == 0) {
+ startAccessibleDrag(position);
+ } else {
+ move(position, mEditIndex, v);
+ }
+ }
+ }).setNegativeButton(android.R.string.cancel, null)
+ .create();
+ SystemUIDialog.setShowForAllUsers(dialog, true);
+ SystemUIDialog.applyFlags(dialog);
+ dialog.show();
+ }
+
+ private void startAccessibleDrag(int position) {
+ mAccessibilityMoving = true;
+ mNeedsFocus = true;
+ mAccessibilityFromIndex = position;
+ // Add placeholder for last slot.
+ mTiles.add(mEditIndex++, null);
+ notifyDataSetChanged();
}
public SpanSizeLookup getSizeLookup() {
return mSizeLookup;
}
+ private boolean move(int from, int to, View v) {
+ if (to >= mEditIndex) {
+ if (from >= mEditIndex) {
+ return false;
+ }
+ // Sort tiles into system/non-system groups.
+ TileInfo tile = mTiles.get(from);
+ if (tile.isSystem) {
+ if (to > mTileDividerIndex) {
+ to = mTileDividerIndex;
+ }
+ } else {
+ if (mTileDividerIndex == mTiles.size()) {
+ mTiles.add(null);
+ }
+ if (to <= mTileDividerIndex) {
+ to = mTileDividerIndex;
+ }
+ }
+ }
+ CharSequence fromLabel = mTiles.get(from).state.label;
+ move(from, to, mTiles);
+ notifyDataSetChanged();
+ updateDividerLocations();
+ CharSequence announcement;
+ if (to >= mEditIndex) {
+ MetricsLogger.action(mContext, MetricsProto.MetricsEvent.ACTION_QS_EDIT_REMOVE_SPEC,
+ strip(mTiles.get(to)));
+ MetricsLogger.action(mContext, MetricsProto.MetricsEvent.ACTION_QS_EDIT_REMOVE,
+ from);
+ announcement = mContext.getString(R.string.accessibility_qs_edit_tile_removed,
+ fromLabel);
+ } else if (from >= mEditIndex) {
+ MetricsLogger.action(mContext, MetricsProto.MetricsEvent.ACTION_QS_EDIT_ADD_SPEC,
+ strip(mTiles.get(to)));
+ MetricsLogger.action(mContext, MetricsProto.MetricsEvent.ACTION_QS_EDIT_ADD,
+ to);
+ announcement = mContext.getString(R.string.accessibility_qs_edit_tile_added,
+ fromLabel, (to + 1));
+ } else {
+ MetricsLogger.action(mContext, MetricsProto.MetricsEvent.ACTION_QS_EDIT_MOVE_SPEC,
+ strip(mTiles.get(to)));
+ MetricsLogger.action(mContext, MetricsProto.MetricsEvent.ACTION_QS_EDIT_MOVE,
+ to);
+ announcement = mContext.getString(R.string.accessibility_qs_edit_tile_moved,
+ fromLabel, (to + 1));
+ }
+ v.announceForAccessibility(announcement);
+ return true;
+ }
+
+ private void updateDividerLocations() {
+ // The first null is the edit tiles label, the second null is the tile divider.
+ // If there is no second null, then there are no non-system tiles.
+ mEditIndex = -1;
+ mTileDividerIndex = mTiles.size();
+ for (int i = 0; i < mTiles.size(); i++) {
+ if (mTiles.get(i) == null) {
+ if (mEditIndex == -1) {
+ mEditIndex = i;
+ } else {
+ mTileDividerIndex = i;
+ }
+ }
+ }
+ if (mTiles.get(mTiles.size() - 1) == null) {
+ mTiles.remove(mTiles.size() - 1);
+ }
+ }
+
+ private String strip(TileInfo tileInfo) {
+ String spec = tileInfo.spec;
+ if (spec.startsWith(CustomTile.PREFIX)) {
+ ComponentName component = CustomTile.getComponentFromSpec(spec);
+ return component.getPackageName();
+ }
+ return spec;
+ }
+
+ private <T> void move(int from, int to, List<T> list) {
+ list.add(from > to ? to : to + 1, list.get(from));
+ list.remove(from > to ? from + 1 : from);
+ }
+
public class Holder extends ViewHolder {
- private QSTileView mTileView;
+ private CustomizeTileView mTileView;
public Holder(View itemView) {
super(itemView);
if (itemView instanceof FrameLayout) {
- mTileView = (QSTileView) ((FrameLayout) itemView).getChildAt(0);
+ mTileView = (CustomizeTileView) ((FrameLayout) itemView).getChildAt(0);
mTileView.setBackground(null);
mTileView.getIcon().disableAnimation();
}
@@ -191,6 +426,9 @@
mTileView.findViewById(R.id.tile_label).animate()
.setDuration(DRAG_LENGTH)
.alpha(0);
+ mTileView.getAppLabel().animate()
+ .setDuration(DRAG_LENGTH)
+ .alpha(0);
}
public void stopDrag() {
@@ -201,13 +439,17 @@
mTileView.findViewById(R.id.tile_label).animate()
.setDuration(DRAG_LENGTH)
.alpha(1);
+ mTileView.getAppLabel().animate()
+ .setDuration(DRAG_LENGTH)
+ .alpha(.6f);
}
}
private final SpanSizeLookup mSizeLookup = new SpanSizeLookup() {
@Override
public int getSpanSize(int position) {
- return getItemViewType(position) == TYPE_EDIT ? 3 : 1;
+ final int type = getItemViewType(position);
+ return type == TYPE_EDIT || type == TYPE_DIVIDER ? 3 : 1;
}
};
@@ -225,7 +467,7 @@
for (int i = 0; i < childCount; i++) {
final View child = parent.getChildAt(i);
final ViewHolder holder = parent.getChildViewHolder(child);
- if (holder.getAdapterPosition() < mDividerIndex) {
+ if (holder.getAdapterPosition() < mEditIndex) {
continue;
}
@@ -267,7 +509,7 @@
mHandler.post(new Runnable() {
@Override
public void run() {
- notifyItemChanged(mDividerIndex);
+ notifyItemChanged(mEditIndex);
}
});
}
@@ -286,20 +528,7 @@
public boolean onMove(RecyclerView recyclerView, ViewHolder viewHolder, ViewHolder target) {
int from = viewHolder.getAdapterPosition();
int to = target.getAdapterPosition();
- if (to > mDividerIndex) {
- if (from >= mDividerIndex) {
- return false;
- }
- }
- move(from, to, mTiles);
- mDividerIndex = mTiles.indexOf(null);
- notifyItemMoved(from, to);
- return true;
- }
-
- private <T> void move(int from, int to, List<T> list) {
- list.add(from > to ? to : to + 1, list.get(from));
- list.remove(from > to ? from + 1 : from);
+ return move(from, to, target.itemView);
}
@Override
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 d95d3ef..d04a2fc 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java
@@ -31,9 +31,9 @@
import com.android.systemui.R;
import com.android.systemui.qs.QSTile;
import com.android.systemui.qs.QSTile.DrawableIcon;
+import com.android.systemui.qs.QSTile.State;
import com.android.systemui.qs.external.CustomTile;
import com.android.systemui.statusbar.phone.QSTileHost;
-import com.android.systemui.tuner.TunerService;
import java.util.ArrayList;
import java.util.Collection;
@@ -75,10 +75,12 @@
public void run() {
final QSTile.State state = tile.newTileState();
tile.getState().copyTo(state);
+ // Ignore the current state and get the generic label instead.
+ state.label = tile.getTileLabel();
mainHandler.post(new Runnable() {
@Override
public void run() {
- addTile(spec, state);
+ addTile(spec, null, state, true);
mListener.onTilesChanged(mTiles);
}
});
@@ -102,28 +104,33 @@
mListener = listener;
}
- private void addTile(String spec, QSTile.State state) {
+ private void addTile(String spec, CharSequence appLabel, State state, boolean isSystem) {
if (mSpecs.contains(spec)) {
return;
}
TileInfo info = new TileInfo();
info.state = state;
info.spec = spec;
+ info.appLabel = appLabel;
+ info.isSystem = isSystem;
mTiles.add(info);
mSpecs.add(spec);
}
- private void addTile(String spec, Drawable drawable, CharSequence label, Context context) {
+ private void addTile(String spec, Drawable drawable, CharSequence label, CharSequence appLabel,
+ Context context) {
QSTile.State state = new QSTile.State();
state.label = label;
state.contentDescription = label;
state.icon = new DrawableIcon(drawable);
- addTile(spec, state);
+ addTile(spec, appLabel, state, false);
}
public static class TileInfo {
public String spec;
+ public CharSequence appLabel;
public QSTile.State state;
+ public boolean isSystem;
}
private class QueryTilesTask extends AsyncTask<Void, Void, Collection<TileInfo>> {
@@ -146,7 +153,8 @@
icon.setTint(mContext.getColor(android.R.color.white));
}
CharSequence label = info.serviceInfo.loadLabel(pm);
- addTile(spec, icon, label != null ? label.toString() : "null", mContext);
+ final CharSequence appLabel = info.serviceInfo.applicationInfo.loadLabel(pm);
+ addTile(spec, icon, label != null ? label.toString() : "null", appLabel, mContext);
}
return tiles;
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java b/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java
index 9156f3a..6114573 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java
@@ -221,6 +221,11 @@
}
@Override
+ public CharSequence getTileLabel() {
+ return getState().label;
+ }
+
+ @Override
protected void handleUpdateState(State state, Object arg) {
Drawable drawable = mTile.getIcon().loadDrawable(mContext);
int tileState = mTile.getState();
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java
index 89f1985b..5f5a87e 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java
@@ -76,6 +76,11 @@
}
@Override
+ public CharSequence getTileLabel() {
+ return mContext.getString(R.string.airplane_mode);
+ }
+
+ @Override
protected void handleUpdateState(BooleanState state, Object arg) {
final int value = arg instanceof Integer ? (Integer)arg : mSetting.getValue();
final boolean airplaneMode = value != 0;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/BatteryTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/BatteryTile.java
index 2e87525..2032783 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/BatteryTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/BatteryTile.java
@@ -21,6 +21,7 @@
import android.content.IntentFilter;
import android.graphics.drawable.Drawable;
import android.os.Handler;
+import android.os.Looper;
import android.text.SpannableStringBuilder;
import android.text.Spanned;
import android.text.style.RelativeSizeSpan;
@@ -44,7 +45,6 @@
public class BatteryTile extends QSTile<QSTile.State> implements BatteryController.BatteryStateChangeCallback {
- private final BatteryMeterDrawable mDrawable;
private final BatteryController mBatteryController;
private final BatteryDetail mBatteryDetail = new BatteryDetail();
@@ -52,13 +52,11 @@
private boolean mPowerSave;
private boolean mCharging;
private boolean mDetailShown;
+ private boolean mPluggedIn;
public BatteryTile(Host host) {
super(host);
mBatteryController = host.getBatteryController();
- mDrawable = new BatteryMeterDrawable(host.getContext(), new Handler(),
- host.getContext().getColor(R.color.batterymeter_frame_color));
- mDrawable.setBatteryController(mBatteryController);
}
@Override
@@ -79,10 +77,8 @@
@Override
public void setListening(boolean listening) {
if (listening) {
- mDrawable.startListening();
mBatteryController.addStateChangedCallback(this);
} else {
- mDrawable.stopListening();
mBatteryController.removeStateChangedCallback(this);
}
}
@@ -106,6 +102,11 @@
}
@Override
+ public CharSequence getTileLabel() {
+ return mContext.getString(R.string.battery);
+ }
+
+ @Override
protected void handleUpdateState(State state, Object arg) {
int level = (arg != null) ? (Integer) arg : mLevel;
String percentage = NumberFormat.getPercentInstance().format((double) level / 100.0);
@@ -113,7 +114,12 @@
state.icon = new Icon() {
@Override
public Drawable getDrawable(Context context) {
- return mDrawable;
+ BatteryMeterDrawable drawable =
+ new BatteryMeterDrawable(context, new Handler(Looper.getMainLooper()),
+ context.getColor(R.color.batterymeter_frame_color));
+ drawable.onBatteryLevelChanged(mLevel, mPluggedIn, mCharging);
+ drawable.onPowerSaveChanged(mPowerSave);
+ return drawable;
}
@Override
@@ -128,6 +134,7 @@
@Override
public void onBatteryLevelChanged(int level, boolean pluggedIn, boolean charging) {
mLevel = level;
+ mPluggedIn = pluggedIn;
mCharging = charging;
refreshState((Integer) level);
if (mDetailShown) {
@@ -138,6 +145,7 @@
@Override
public void onPowerSaveChanged(boolean isPowerSave) {
mPowerSave = isPowerSave;
+ refreshState(null);
if (mDetailShown) {
mBatteryDetail.postBindView();
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
index 80f667c..1fef8f1 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
@@ -96,6 +96,11 @@
}
@Override
+ public CharSequence getTileLabel() {
+ return mContext.getString(R.string.quick_settings_bluetooth_label);
+ }
+
+ @Override
protected void handleUpdateState(BooleanState state, Object arg) {
final boolean enabled = mController.isBluetoothEnabled();
final boolean connected = mController.isBluetoothConnected();
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
index e0ad002..bea1e15 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
@@ -108,6 +108,11 @@
}
@Override
+ public CharSequence getTileLabel() {
+ return mContext.getString(R.string.quick_settings_cast_title);
+ }
+
+ @Override
protected void handleUpdateState(BooleanState state, Object arg) {
state.label = mContext.getString(R.string.quick_settings_cast_title);
state.value = false;
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 5f87741..55b00b5 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
@@ -101,6 +101,11 @@
}
@Override
+ public CharSequence getTileLabel() {
+ return mContext.getString(R.string.quick_settings_cellular_detail_title);
+ }
+
+ @Override
protected void handleUpdateState(SignalState state, Object arg) {
CallbackInfo cb = (CallbackInfo) arg;
if (cb == null) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java
index a608316..416132e 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java
@@ -85,6 +85,11 @@
}
@Override
+ public CharSequence getTileLabel() {
+ return mContext.getString(R.string.quick_settings_inversion_label);
+ }
+
+ @Override
protected void handleUpdateState(BooleanState state, Object arg) {
final int value = arg instanceof Integer ? (Integer) arg : mSetting.getValue();
final boolean enabled = value != 0;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/DataSaverTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/DataSaverTile.java
index 74b3fdc..35aff21 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/DataSaverTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/DataSaverTile.java
@@ -57,6 +57,11 @@
}
@Override
+ public CharSequence getTileLabel() {
+ return mContext.getString(R.string.data_saver);
+ }
+
+ @Override
protected void handleUpdateState(BooleanState state, Object arg) {
state.value = arg instanceof Boolean ? (Boolean) arg
: mDataSaverController.isDataSaverEnabled();
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
index 8b22868..11efd56 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
@@ -128,6 +128,11 @@
}
@Override
+ public CharSequence getTileLabel() {
+ return mContext.getString(R.string.quick_settings_dnd_label);
+ }
+
+ @Override
protected void handleUpdateState(BooleanState state, Object arg) {
final int zen = arg instanceof Integer ? (Integer) arg : mController.getZen();
final boolean newValue = zen != Global.ZEN_MODE_OFF;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java
index a01a9a5..69e71bc 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java
@@ -87,6 +87,16 @@
}
@Override
+ public CharSequence getTileLabel() {
+ return mContext.getString(R.string.quick_settings_flashlight_label);
+ }
+
+ @Override
+ protected void handleLongClick() {
+ handleClick();
+ }
+
+ @Override
protected void handleUpdateState(BooleanState state, Object arg) {
state.label = mHost.getContext().getString(R.string.quick_settings_flashlight_label);
if (!mFlashlightController.isAvailable()) {
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 da93120..bf5b22c 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
@@ -74,6 +74,11 @@
}
@Override
+ public CharSequence getTileLabel() {
+ return mContext.getString(R.string.quick_settings_hotspot_label);
+ }
+
+ @Override
protected void handleUpdateState(BooleanState state, Object arg) {
state.label = mContext.getString(R.string.quick_settings_hotspot_label);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/IntentTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/IntentTile.java
index bb5ff8e..2a2cc46 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/IntentTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/IntentTile.java
@@ -119,6 +119,11 @@
}
@Override
+ public CharSequence getTileLabel() {
+ return getState().label;
+ }
+
+ @Override
protected void handleUpdateState(State state, Object arg) {
Intent intent = (Intent) arg;
if (intent == null) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java
index b1d1c77..6286f5e 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java
@@ -89,6 +89,11 @@
}
@Override
+ public CharSequence getTileLabel() {
+ return mContext.getString(R.string.quick_settings_location_label);
+ }
+
+ @Override
protected void handleUpdateState(BooleanState state, Object arg) {
final boolean locationEnabled = mController.isLocationEnabled();
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java
index d80ca10..38b3706 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java
@@ -80,6 +80,11 @@
}
@Override
+ public CharSequence getTileLabel() {
+ return getState().label;
+ }
+
+ @Override
protected void handleUpdateState(BooleanState state, Object arg) {
if (mController == null) return;
final boolean rotationLocked = arg != null ? (Boolean) arg
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/UserTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserTile.java
index f1066c1..5b4279c 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/UserTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserTile.java
@@ -73,6 +73,11 @@
}
@Override
+ public CharSequence getTileLabel() {
+ return getState().label;
+ }
+
+ @Override
protected void handleUpdateState(State state, Object arg) {
final Pair<String, Drawable> p = arg != null ? (Pair<String, Drawable>) arg : mLastUpdate;
if (p != null) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
index 7ee795f..c72bbf3 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
@@ -119,6 +119,11 @@
}
@Override
+ public CharSequence getTileLabel() {
+ return mContext.getString(R.string.quick_settings_wifi_label);
+ }
+
+ @Override
protected void handleUpdateState(SignalState state, Object arg) {
if (DEBUG) Log.d(TAG, "handleUpdateState arg=" + arg);
CallbackInfo cb = (CallbackInfo) arg;
@@ -149,7 +154,7 @@
state.label = removeDoubleQuotes(cb.enabledDesc);
signalContentDescription = cb.wifiSignalContentDescription;
} else if (wifiNotConnected) {
- state.icon = ResourceIcon.get(R.drawable.ic_qs_wifi_full_0);
+ state.icon = ResourceIcon.get(R.drawable.ic_qs_wifi_disconnected);
state.label = r.getString(R.string.quick_settings_wifi_label);
signalContentDescription = r.getString(R.string.accessibility_no_wifi);
} else {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/WorkModeTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/WorkModeTile.java
index 421a2cf..2c5f7d5 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/WorkModeTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/WorkModeTile.java
@@ -82,6 +82,11 @@
}
@Override
+ public CharSequence getTileLabel() {
+ return mContext.getString(R.string.quick_settings_work_mode_label);
+ }
+
+ @Override
protected void handleUpdateState(BooleanState state, Object arg) {
if (arg instanceof Boolean) {
state.value = (Boolean) arg;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
index fe7ac71..8060e07 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
@@ -90,6 +90,7 @@
private RecentsPackageMonitor mPackageMonitor;
private long mLastTabKeyEventTime;
+ private int mLastOrientation = Configuration.ORIENTATION_UNDEFINED;
private boolean mFinishedOnStartup;
private boolean mIgnoreAltTabRelease;
private boolean mIsVisible;
@@ -266,6 +267,7 @@
getWindow().getAttributes().privateFlags |=
WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DECOR_VIEW_VISIBILITY;
+ mLastOrientation = getResources().getConfiguration().orientation;
mFocusTimerDuration = getResources().getInteger(R.integer.recents_auto_advance_duration);
mIterateTrigger = new DozeTrigger(mFocusTimerDuration, new Runnable() {
@Override
@@ -274,6 +276,9 @@
}
});
+ // Set the window background
+ getWindow().setBackgroundDrawable(mRecentsView.getBackgroundScrim());
+
// Create the home intent runnable
mHomeIntent = new Intent(Intent.ACTION_MAIN, null);
mHomeIntent.addCategory(Intent.CATEGORY_HOME);
@@ -338,8 +343,8 @@
mRecentsView.updateStack(stack);
// Update the nav bar scrim, but defer the animation until the enter-window event
- boolean animateNavBarScrim = !launchState.launchedWhileDocking;
- updateNavBarScrim(animateNavBarScrim, null);
+ boolean animateNavBarScrim = !launchState.launchedViaDockGesture;
+ mScrimViews.updateNavBarScrim(animateNavBarScrim, stack.getTaskCount() > 0, null);
// If this is a new instance relaunched by AM, without going through the normal mechanisms,
// then we have to manually trigger the enter animation state
@@ -412,34 +417,43 @@
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
- // Update the nav bar for the current orientation
- updateNavBarScrim(false /* animateNavBarScrim */, AnimationProps.IMMEDIATE);
- EventBus.getDefault().send(new ConfigurationChangedEvent(false /* fromMultiWindow */));
+ // Notify of the config change
+ int newOrientation = getResources().getConfiguration().orientation;
+ int numStackTasks = mRecentsView.getStack().getStackTaskCount();
+ EventBus.getDefault().send(new ConfigurationChangedEvent(false /* fromMultiWindow */,
+ (mLastOrientation != newOrientation), numStackTasks > 0));
+ mLastOrientation = newOrientation;
}
@Override
- public void onMultiWindowChanged(boolean inMultiWindow) {
- super.onMultiWindowChanged(inMultiWindow);
- EventBus.getDefault().send(new ConfigurationChangedEvent(true /* fromMultiWindow */));
+ public void onMultiWindowModeChanged(boolean isInMultiWindowMode) {
+ super.onMultiWindowModeChanged(isInMultiWindowMode);
+
+ // Reload the task stack completely
+ RecentsConfiguration config = Recents.getConfiguration();
+ RecentsActivityLaunchState launchState = config.getLaunchState();
+ RecentsTaskLoader loader = Recents.getTaskLoader();
+ RecentsTaskLoadPlan loadPlan = loader.createLoadPlan(this);
+ loader.preloadTasks(loadPlan, -1 /* topTaskId */, false /* isTopTaskHome */);
+
+ RecentsTaskLoadPlan.Options loadOpts = new RecentsTaskLoadPlan.Options();
+ loadOpts.numVisibleTasks = launchState.launchedNumVisibleTasks;
+ loadOpts.numVisibleTaskThumbnails = launchState.launchedNumVisibleThumbnails;
+ loader.loadTasks(this, loadPlan, loadOpts);
+
+ TaskStack stack = loadPlan.getTaskStack();
+ int numStackTasks = stack.getStackTaskCount();
+
+ EventBus.getDefault().send(new ConfigurationChangedEvent(true /* fromMultiWindow */,
+ false /* fromOrientationChange */, numStackTasks > 0));
if (mRecentsView != null) {
- // Reload the task stack completely
- RecentsConfiguration config = Recents.getConfiguration();
- RecentsActivityLaunchState launchState = config.getLaunchState();
- RecentsTaskLoader loader = Recents.getTaskLoader();
- RecentsTaskLoadPlan loadPlan = loader.createLoadPlan(this);
- loader.preloadTasks(loadPlan, -1 /* topTaskId */, false /* isTopTaskHome */);
-
- RecentsTaskLoadPlan.Options loadOpts = new RecentsTaskLoadPlan.Options();
- loadOpts.numVisibleTasks = launchState.launchedNumVisibleTasks;
- loadOpts.numVisibleTaskThumbnails = launchState.launchedNumVisibleThumbnails;
- loader.loadTasks(this, loadPlan, loadOpts);
-
- mRecentsView.updateStack(loadPlan.getTaskStack());
+ mRecentsView.updateStack(stack);
}
- EventBus.getDefault().send(new MultiWindowStateChangedEvent(inMultiWindow));
+ EventBus.getDefault().send(new MultiWindowStateChangedEvent(isInMultiWindowMode,
+ numStackTasks > 0));
}
@Override
@@ -719,18 +733,4 @@
});
return true;
}
-
- /**
- * Updates the nav bar scrim.
- */
- private void updateNavBarScrim(boolean animateNavBarScrim, AnimationProps animation) {
- // Animate the SystemUI scrims into view
- SystemServicesProxy ssp = Recents.getSystemServices();
- int taskCount = mRecentsView.getStack().getTaskCount();
- boolean hasNavBarScrim = (taskCount > 0) && !ssp.hasTransposedNavBar();
- mScrimViews.prepareEnterRecentsAnimation(hasNavBarScrim, animateNavBarScrim);
- if (animateNavBarScrim && animation != null) {
- mScrimViews.animateNavBarScrimVisibility(true, animation);
- }
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivityLaunchState.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivityLaunchState.java
index 77f7739..7161053 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivityLaunchState.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivityLaunchState.java
@@ -29,10 +29,9 @@
public boolean launchedWithAltTab;
public boolean launchedFromApp;
- public boolean launchedFromAppDocked;
public boolean launchedFromHome;
public boolean launchedViaDragGesture;
- public boolean launchedWhileDocking;
+ public boolean launchedViaDockGesture;
public int launchedToTaskId;
public int launchedNumVisibleTasks;
public int launchedNumVisibleThumbnails;
@@ -40,18 +39,10 @@
public void reset() {
launchedFromHome = false;
launchedFromApp = false;
- launchedFromAppDocked = false;
launchedToTaskId = -1;
launchedWithAltTab = false;
launchedViaDragGesture = false;
- launchedWhileDocking = false;
- }
-
- /** Called when the configuration has changed, and we want to reset any configuration specific
- * members. */
- public void updateOnConfigurationChange() {
- launchedViaDragGesture = false;
- launchedWhileDocking = false;
+ launchedViaDockGesture = false;
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
index 40613f0..73c6e6e 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
@@ -80,12 +80,4 @@
public RecentsActivityLaunchState getLaunchState() {
return mLaunchState;
}
-
- /**
- * Called when the configuration has changed, and we want to reset any configuration specific
- * members.
- */
- public void updateOnConfigurationChange() {
- mLaunchState.updateOnConfigurationChange();
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsDebugFlags.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsDebugFlags.java
index 043510e..1715356 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsDebugFlags.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsDebugFlags.java
@@ -36,7 +36,7 @@
// Enables the task affiliations
public static final boolean EnableAffiliatedTaskGroups = false;
// TODO: To be repurposed
- public static final boolean EnableStackActionButton = false;
+ public static final boolean EnableStackActionButton = true;
// Overrides the Tuner flags and enables the timeout
private static final boolean EnableFastToggleTimeout = false;
// Overrides the Tuner flags and enables the paging via the Recents button
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
index 7daef64..4dae746 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
@@ -43,7 +43,6 @@
import com.android.systemui.R;
import com.android.systemui.SystemUIApplication;
import com.android.systemui.recents.events.EventBus;
-import com.android.systemui.recents.events.EventBus.Event;
import com.android.systemui.recents.events.activity.DockedTopTaskEvent;
import com.android.systemui.recents.events.activity.EnterRecentsWindowLastAnimationFrameEvent;
import com.android.systemui.recents.events.activity.ForcedResizableEvent;
@@ -208,7 +207,6 @@
public void onConfigurationChanged() {
reloadHeaderBarLayout();
updateHeaderBarLayout(null /* stack */);
- Recents.getConfiguration().updateOnConfigurationChange();
}
/**
@@ -438,7 +436,7 @@
}
// Launch the task
- ssp.startActivityFromRecents(mContext, toTask.key.id, toTask.title, launchOpts);
+ ssp.startActivityFromRecents(mContext, toTask.key, toTask.title, launchOpts);
}
/**
@@ -510,7 +508,7 @@
MetricsLogger.count(mContext, "overview_affiliated_task_launch", 1);
// Launch the task
- ssp.startActivityFromRecents(mContext, toTask.key.id, toTask.title, launchOpts);
+ ssp.startActivityFromRecents(mContext, toTask.key, toTask.title, launchOpts);
}
public void showNextAffiliatedTask() {
@@ -586,18 +584,24 @@
Rect systemInsets = new Rect();
ssp.getStableInsets(systemInsets);
Rect windowRect = ssp.getWindowRect();
+ // When docked, the nav bar insets are consumed and the activity is measured without insets.
+ // However, the window bounds include the insets, so we need to subtract them here to make
+ // them identical.
+ if (ssp.hasDockedTask()) {
+ windowRect.bottom -= systemInsets.bottom;
+ systemInsets.bottom = 0;
+ }
calculateWindowStableInsets(systemInsets, windowRect);
windowRect.offsetTo(0, 0);
TaskStackLayoutAlgorithm stackLayout = mDummyStackView.getStackAlgorithm();
- stackLayout.getTaskStackBounds(windowRect, systemInsets.top, systemInsets.right,
- mTaskStackBounds);
// Rebind the header bar and draw it for the transition
- Rect taskStackBounds = new Rect(mTaskStackBounds);
stackLayout.setSystemInsets(systemInsets);
if (stack != null) {
- stackLayout.initialize(windowRect, taskStackBounds,
+ stackLayout.getTaskStackBounds(windowRect, systemInsets.top, systemInsets.right,
+ mTaskStackBounds);
+ stackLayout.initialize(windowRect, mTaskStackBounds,
TaskStackLayoutAlgorithm.StackState.getStackStateForStack(stack));
mDummyStackView.setTasks(stack, false /* allowNotifyStackChanges */);
}
@@ -665,13 +669,18 @@
@Override
public void run() {
final Bitmap transitionBitmap = drawThumbnailTransitionBitmap(toTask, toTransform);
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- mThumbnailTransitionBitmapCache = transitionBitmap;
- mThumbnailTransitionBitmapCacheKey = toTask;
- }
- });
+ if (transitionBitmap != null) {
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ mThumbnailTransitionBitmapCache = transitionBitmap;
+ mThumbnailTransitionBitmapCacheKey = toTask;
+ }
+ });
+ } else {
+ Log.e(TAG, "Could not load thumbnail for task: " + toTask + " at transform: " +
+ toTransform);
+ }
}
});
}
@@ -776,7 +785,7 @@
// Get the transform for the running task
stackView.updateLayoutAlgorithm(true /* boundScroll */);
stackView.updateToInitialState(true /* scrollToInitialState */);
- mTmpTransform = stackView.getStackAlgorithm().getStackTransformScreenCoordinates(launchTask,
+ stackView.getStackAlgorithm().getStackTransformScreenCoordinates(launchTask,
stackView.getScroller().getStackScroll(), mTmpTransform, null);
return mTmpTransform;
}
@@ -791,6 +800,9 @@
synchronized (mHeaderBarLock) {
int toHeaderWidth = (int) toTransform.rect.width();
int toHeaderHeight = (int) (mHeaderBar.getMeasuredHeight() * toTransform.scale);
+ if (toHeaderWidth <= 0 || toHeaderHeight <= 0) {
+ return null;
+ }
boolean disabledInSafeMode = !toTask.isSystemApp && ssp.isInSafeMode();
mHeaderBar.onTaskViewSizeChanged((int) toTransform.rect.width(),
(int) toTransform.rect.height());
@@ -852,13 +864,12 @@
// Update the launch state
launchState.launchedFromHome = false;
launchState.launchedFromApp = mLaunchedWhileDocking;
+ launchState.launchedViaDockGesture = mLaunchedWhileDocking;
launchState.launchedToTaskId = (topTask != null) ? topTask.id : -1;
- launchState.launchedFromAppDocked = mLaunchedWhileDocking;
launchState.launchedWithAltTab = mTriggeredFromAltTab;
launchState.launchedNumVisibleTasks = stackVr.numVisibleTasks;
launchState.launchedNumVisibleThumbnails = stackVr.numVisibleThumbnails;
launchState.launchedViaDragGesture = mDraggingInRecents;
- launchState.launchedWhileDocking = mLaunchedWhileDocking;
if (!animate) {
startRecentsActivity(ActivityOptions.makeCustomAnimation(mContext, -1, -1));
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/activity/ConfigurationChangedEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/activity/ConfigurationChangedEvent.java
index c234c34..e3bc2a7 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/events/activity/ConfigurationChangedEvent.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/activity/ConfigurationChangedEvent.java
@@ -24,8 +24,13 @@
public class ConfigurationChangedEvent extends EventBus.AnimatedEvent {
public final boolean fromMultiWindow;
+ public final boolean fromOrientationChange;
+ public final boolean hasStackTasks;
- public ConfigurationChangedEvent(boolean fromMultiWindow) {
+ public ConfigurationChangedEvent(boolean fromMultiWindow, boolean fromOrientationChange,
+ boolean hasStackTasks) {
this.fromMultiWindow = fromMultiWindow;
+ this.fromOrientationChange = fromOrientationChange;
+ this.hasStackTasks = hasStackTasks;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/activity/MultiWindowStateChangedEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/activity/MultiWindowStateChangedEvent.java
index 19245d9..cf2a68e 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/events/activity/MultiWindowStateChangedEvent.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/activity/MultiWindowStateChangedEvent.java
@@ -24,8 +24,10 @@
public class MultiWindowStateChangedEvent extends EventBus.Event {
public final boolean inMultiWindow;
+ public final boolean hasStackTasks;
- public MultiWindowStateChangedEvent(boolean inMultiWindow) {
+ public MultiWindowStateChangedEvent(boolean inMultiWindow, boolean hasStackTasks) {
this.inMultiWindow = inMultiWindow;
+ this.hasStackTasks = hasStackTasks;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/ui/ResetBackgroundScrimEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/ui/DismissAllTaskViewsEvent.java
similarity index 78%
rename from packages/SystemUI/src/com/android/systemui/recents/events/ui/ResetBackgroundScrimEvent.java
rename to packages/SystemUI/src/com/android/systemui/recents/events/ui/DismissAllTaskViewsEvent.java
index 863f40b..f8b59c7 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/events/ui/ResetBackgroundScrimEvent.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/ui/DismissAllTaskViewsEvent.java
@@ -17,10 +17,11 @@
package com.android.systemui.recents.events.ui;
import com.android.systemui.recents.events.EventBus;
+import com.android.systemui.recents.views.TaskView;
/**
- * This is sent to reset the background scrim back to the initial state.
+ * This event is sent to request that all the {@link TaskView}s are dismissed.
*/
-public class ResetBackgroundScrimEvent extends EventBus.Event {
+public class DismissAllTaskViewsEvent extends EventBus.AnimatedEvent {
// Simple event
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/ui/DismissTaskViewEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/ui/DismissTaskViewEvent.java
index 1165f4e..1f8c644 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/events/ui/DismissTaskViewEvent.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/ui/DismissTaskViewEvent.java
@@ -17,7 +17,6 @@
package com.android.systemui.recents.events.ui;
import com.android.systemui.recents.events.EventBus;
-import com.android.systemui.recents.model.Task;
import com.android.systemui.recents.views.TaskView;
/**
@@ -26,10 +25,8 @@
public class DismissTaskViewEvent extends EventBus.AnimatedEvent {
public final TaskView taskView;
- public final Task task;
- public DismissTaskViewEvent(TaskView taskView, Task task) {
+ public DismissTaskViewEvent(TaskView taskView) {
this.taskView = taskView;
- this.task = task;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/ui/UpdateBackgroundScrimEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/ui/UpdateBackgroundScrimEvent.java
deleted file mode 100644
index fdd4c67..0000000
--- a/packages/SystemUI/src/com/android/systemui/recents/events/ui/UpdateBackgroundScrimEvent.java
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.recents.events.ui;
-
-import com.android.systemui.recents.events.EventBus;
-
-/**
- * This is sent to request an update to the background scrim.
- */
-public class UpdateBackgroundScrimEvent extends EventBus.Event {
-
- public final float alpha;
-
- public UpdateBackgroundScrimEvent(float alpha) {
- this.alpha = alpha;
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/ui/dragndrop/DragDropTargetChangedEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/ui/dragndrop/DragDropTargetChangedEvent.java
index b85ddac..216be61 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/events/ui/dragndrop/DragDropTargetChangedEvent.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/ui/dragndrop/DragDropTargetChangedEvent.java
@@ -23,7 +23,7 @@
/**
* This event is sent when a user drags in/out of a drop target.
*/
-public class DragDropTargetChangedEvent extends EventBus.Event {
+public class DragDropTargetChangedEvent extends EventBus.AnimatedEvent {
// The task that is currently being dragged
public final Task task;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
index 3b759c0..1a4b40f 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
@@ -18,6 +18,7 @@
import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID;
+import static android.app.ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID;
import static android.app.ActivityManager.StackId.HOME_STACK_ID;
import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
import static android.provider.Settings.Global.DEVELOPMENT_ENABLE_FREEFORM_WINDOWS_SUPPORT;
@@ -77,6 +78,7 @@
import com.android.systemui.R;
import com.android.systemui.recents.RecentsDebugFlags;
import com.android.systemui.recents.RecentsImpl;
+import com.android.systemui.recents.model.Task;
import com.android.systemui.recents.tv.RecentsTvImpl;
import com.android.systemui.recents.model.ThumbnailData;
@@ -284,7 +286,7 @@
int numTasksToQuery = Math.max(minNumTasksToQuery, numLatestTasks);
List<ActivityManager.RecentTaskInfo> tasks = mAm.getRecentTasksForUser(numTasksToQuery,
ActivityManager.RECENT_IGNORE_HOME_STACK_TASKS |
- ActivityManager.RECENT_INGORE_DOCKED_STACK_TASKS |
+ ActivityManager.RECENT_INGORE_DOCKED_STACK_TOP_TASK |
ActivityManager.RECENT_INGORE_PINNED_STACK_TASKS |
ActivityManager.RECENT_IGNORE_UNAVAILABLE |
ActivityManager.RECENT_INCLUDE_PROFILES |
@@ -962,11 +964,20 @@
}
/** Starts an activity from recents. */
- public boolean startActivityFromRecents(Context context, int taskId, String taskName,
+ public boolean startActivityFromRecents(Context context, Task.TaskKey taskKey, String taskName,
ActivityOptions options) {
if (mIam != null) {
try {
- mIam.startActivityFromRecents(taskId, options == null ? null : options.toBundle());
+ if (taskKey.stackId == DOCKED_STACK_ID) {
+ // We show non-visible docked tasks in Recents, but we always want to launch
+ // them in the fullscreen stack.
+ if (options == null) {
+ options = ActivityOptions.makeBasic();
+ }
+ options.setLaunchStackId(FULLSCREEN_WORKSPACE_STACK_ID);
+ }
+ mIam.startActivityFromRecents(
+ taskKey.id, options == null ? null : options.toBundle());
return true;
} catch (Exception e) {
Log.e(TAG, context.getString(R.string.recents_launch_error_message, taskName), e);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java
index 76ca6ca..7aeff1f 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java
@@ -132,6 +132,8 @@
SparseIntArray affiliatedTaskCounts = new SparseIntArray();
String dismissDescFormat = mContext.getString(
R.string.accessibility_recents_item_will_be_dismissed);
+ String appInfoDescFormat = mContext.getString(
+ R.string.accessibility_recents_item_open_app_info);
long lastStackActiveTime = Prefs.getLong(mContext,
Prefs.Key.OVERVIEW_LAST_STACK_TASK_ACTIVE_TIME, 0);
if (RecentsDebugFlags.Static.EnableMockTasks) {
@@ -188,8 +190,9 @@
// Load the title, icon, and color
ActivityInfo info = loader.getAndUpdateActivityInfo(taskKey);
String title = loader.getAndUpdateActivityTitle(taskKey, t.taskDescription);
- String contentDescription = loader.getAndUpdateContentDescription(taskKey, res);
- String dismissDescription = String.format(dismissDescFormat, contentDescription);
+ String titleDescription = loader.getAndUpdateContentDescription(taskKey, res);
+ String dismissDescription = String.format(dismissDescFormat, titleDescription);
+ String appInfoDescription = String.format(appInfoDescFormat, titleDescription);
Drawable icon = isStackTask
? loader.getAndUpdateActivityIcon(taskKey, t.taskDescription, res, false)
: null;
@@ -201,9 +204,9 @@
// Add the task to the stack
Task task = new Task(taskKey, t.affiliatedTaskId, t.affiliatedTaskColor, icon,
- thumbnail, title, contentDescription, dismissDescription, activityColor,
- backgroundColor, isLaunchTarget, isStackTask, isSystemApp, t.isDockable,
- t.bounds, t.taskDescription);
+ thumbnail, title, titleDescription, dismissDescription, appInfoDescription,
+ activityColor, backgroundColor, isLaunchTarget, isStackTask, isSystemApp,
+ t.isDockable, t.bounds, t.taskDescription);
allTasks.add(task);
affiliatedTaskCounts.put(taskKey.id, affiliatedTaskCounts.get(taskKey.id, 0) + 1);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/Task.java b/packages/SystemUI/src/com/android/systemui/recents/model/Task.java
index d5d5aa0..6668079 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/Task.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/Task.java
@@ -134,10 +134,12 @@
@ViewDebug.ExportedProperty(category="recents")
public String title;
@ViewDebug.ExportedProperty(category="recents")
- public String contentDescription;
+ public String titleDescription;
@ViewDebug.ExportedProperty(category="recents")
public String dismissDescription;
@ViewDebug.ExportedProperty(category="recents")
+ public String appInfoDescription;
+ @ViewDebug.ExportedProperty(category="recents")
public int colorPrimary;
@ViewDebug.ExportedProperty(category="recents")
public int colorBackground;
@@ -174,8 +176,8 @@
}
public Task(TaskKey key, int affiliationTaskId, int affiliationColor, Drawable icon,
- Bitmap thumbnail, String title, String contentDescription,
- String dismissDescription, int colorPrimary, int colorBackground,
+ Bitmap thumbnail, String title, String titleDescription, String dismissDescription,
+ String appInfoDescription, int colorPrimary, int colorBackground,
boolean isLaunchTarget, boolean isStackTask, boolean isSystemApp,
boolean isDockable, Rect bounds, ActivityManager.TaskDescription taskDescription) {
boolean isInAffiliationGroup = (affiliationTaskId != key.id);
@@ -186,8 +188,9 @@
this.icon = icon;
this.thumbnail = thumbnail;
this.title = title;
- this.contentDescription = contentDescription;
+ this.titleDescription = titleDescription;
this.dismissDescription = dismissDescription;
+ this.appInfoDescription = appInfoDescription;
this.colorPrimary = hasAffiliationGroupColor ? affiliationColor : colorPrimary;
this.colorBackground = colorBackground;
this.useLightOnPrimaryColor = Utilities.computeContrastBetweenColors(this.colorPrimary,
@@ -211,8 +214,9 @@
this.icon = o.icon;
this.thumbnail = o.thumbnail;
this.title = o.title;
- this.contentDescription = o.contentDescription;
+ this.titleDescription = o.titleDescription;
this.dismissDescription = o.dismissDescription;
+ this.appInfoDescription = o.appInfoDescription;
this.colorPrimary = o.colorPrimary;
this.colorBackground = o.colorBackground;
this.useLightOnPrimaryColor = o.useLightOnPrimaryColor;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java b/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java
index 5a2507d..df3f56c 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java
@@ -222,6 +222,11 @@
Task newFrontMostTask, AnimationProps animation, boolean fromDockGesture);
/**
+ * Notifies when all tasks have been removed from the stack.
+ */
+ void onStackTasksRemoved(TaskStack stack);
+
+ /**
* Notifies when tasks in the stack have been updated.
*/
void onStackTasksUpdated(TaskStack stack);
@@ -510,6 +515,22 @@
}
/**
+ * Removes all tasks from the stack.
+ */
+ public void removeAllTasks() {
+ ArrayList<Task> tasks = mStackTaskList.getTasks();
+ for (int i = tasks.size() - 1; i >= 0; i--) {
+ Task t = tasks.get(i);
+ removeTaskImpl(mStackTaskList, t);
+ mRawTaskList.remove(t);
+ }
+ if (mCb != null) {
+ // Notify that all tasks have been removed
+ mCb.onStackTasksRemoved(this);
+ }
+ }
+
+ /**
* Sets a few tasks in one go, without calling any callbacks.
*
* @param tasks the new set of tasks to replace the current set.
diff --git a/packages/SystemUI/src/com/android/systemui/recents/tv/RecentsTvActivity.java b/packages/SystemUI/src/com/android/systemui/recents/tv/RecentsTvActivity.java
index 134b90c..483f9e5 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/tv/RecentsTvActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/tv/RecentsTvActivity.java
@@ -15,8 +15,6 @@
*/
package com.android.systemui.recents.tv;
-import android.animation.AnimatorInflater;
-import android.animation.AnimatorSet;
import android.app.Activity;
import android.app.ActivityOptions;
import android.content.Intent;
@@ -55,11 +53,12 @@
import com.android.systemui.recents.model.RecentsTaskLoader;
import com.android.systemui.recents.model.Task;
import com.android.systemui.recents.model.TaskStack;
+import com.android.systemui.recents.tv.animations.FocusAnimationHolder;
import com.android.systemui.recents.tv.views.RecentsTvView;
import com.android.systemui.recents.tv.views.TaskStackHorizontalViewAdapter;
import com.android.systemui.statusbar.BaseStatusBar;
import com.android.systemui.tv.pip.PipManager;
-import com.android.systemui.tv.pip.PipControlsView;
+import com.android.systemui.tv.pip.PipRecentsOverlayManager;
import java.util.ArrayList;
import java.util.Collections;
@@ -80,15 +79,13 @@
private boolean mIgnoreAltTabRelease;
private RecentsTvView mRecentsView;
- private PipControlsView mPipControlsView;
- private View mPipShadeView;
- private AnimatorSet mPipControlsViewFadeInAnimator;
- private AnimatorSet mPipControlsViewFadeOutAnimator;
+ private FocusAnimationHolder mRecentsFocusAnimationHolder;
+ private View mPipView;
private TaskStackHorizontalViewAdapter mTaskStackViewAdapter;
private FinishRecentsRunnable mFinishLaunchHomeRunnable;
- private PipManager mPipManager;
- private PipManager.Listener mPipListener = new PipManager.Listener() {
+ private final PipManager mPipManager = PipManager.getInstance();
+ private final PipManager.Listener mPipListener = new PipManager.Listener() {
@Override
public void onPipEntered() {
updatePipUI();
@@ -113,10 +110,38 @@
@Override
public void onPipResizeAboutToStart() { }
-
- @Override
- public void onMediaControllerChanged() { }
};
+ private PipRecentsOverlayManager mPipRecentsOverlayManager;
+ private final PipRecentsOverlayManager.Callback mPipRecentsOverlayManagerCallback =
+ new PipRecentsOverlayManager.Callback() {
+ @Override
+ public void onClosed() {
+ dismissRecentsToLaunchTargetTaskOrHome();
+ }
+
+ @Override
+ public void onBackPressed() {
+ RecentsTvActivity.this.onBackPressed();
+ }
+
+ @Override
+ public void onRecentsFocused() {
+ mRecentsView.requestFocus();
+ }
+ };
+ private final View.OnFocusChangeListener mPipViewFocusChangeListener =
+ new View.OnFocusChangeListener() {
+ @Override
+ public void onFocusChange(View v, boolean hasFocus) {
+ if (hasFocus) {
+ mRecentsFocusAnimationHolder.startFocusLoseAnimation();
+ mPipRecentsOverlayManager.requestFocus(
+ mTaskStackViewAdapter.getItemCount() > 0);
+ } else {
+ mRecentsFocusAnimationHolder.startFocusGainAnimation();
+ }
+ }
+ };
/**
* A common Runnable to finish Recents by launching Home with an animation depending on the
@@ -248,7 +273,7 @@
finish();
return;
}
- mPipManager = PipManager.getInstance();
+ mPipRecentsOverlayManager = PipManager.getInstance().getPipRecentsOverlayManager();
// Register this activity with the event bus
EventBus.getDefault().register(this, EVENT_BUS_PRIORITY);
@@ -263,21 +288,19 @@
mRecentsView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE |
View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN |
View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION);
- mPipControlsView = (PipControlsView) findViewById(R.id.pip_controls);
- mPipControlsView.setListener(new PipControlsView.Listener() {
- @Override
- public void onClosed() {
- dismissRecentsToLaunchTargetTaskOrHome();
- }
- });
- mPipShadeView = findViewById(R.id.pip_shade);
+ mRecentsFocusAnimationHolder = new FocusAnimationHolder(mRecentsView);
- mPipControlsViewFadeInAnimator = (AnimatorSet) AnimatorInflater.loadAnimator(this,
- R.anim.tv_pip_controls_fade_in);
- mPipControlsViewFadeInAnimator.setTarget(mPipControlsView);
- mPipControlsViewFadeOutAnimator = (AnimatorSet) AnimatorInflater.loadAnimator(this,
- R.anim.tv_pip_controls_fade_out);
- mPipControlsViewFadeOutAnimator.setTarget(mPipControlsView);
+ mPipView = findViewById(R.id.pip);
+ // Place mPipView at the PIP bounds for fine tuned focus handling.
+ Rect pipBounds = mPipManager.getPipBounds();
+ LayoutParams lp = (LayoutParams) mPipView.getLayoutParams();
+ lp.width = pipBounds.width();
+ lp.height = pipBounds.height();
+ lp.leftMargin = pipBounds.left;
+ lp.topMargin = pipBounds.top;
+ mPipView.setLayoutParams(lp);
+
+ mPipRecentsOverlayManager.setCallback(mPipRecentsOverlayManagerCallback);
getWindow().getAttributes().privateFlags |=
WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DECOR_VIEW_VISIBILITY;
@@ -289,7 +312,6 @@
Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
mFinishLaunchHomeRunnable = new FinishRecentsRunnable(homeIntent);
- updatePipUI();
mPipManager.addListener(mPipListener);
}
@@ -321,9 +343,7 @@
SystemServicesProxy ssp = Recents.getSystemServices();
EventBus.getDefault().send(new RecentsVisibilityChangedEvent(this, true));
- mPipManager.onRecentsStarted();
- // Give focus to the recents row whenever its visible to an user.
- mRecentsView.requestFocus();
+ updatePipUI();
}
@Override
@@ -333,10 +353,21 @@
}
@Override
+ public void onResume() {
+ super.onResume();
+ mPipRecentsOverlayManager.onRecentsResumed();
+ }
+
+ @Override
+ public void onPause() {
+ super.onPause();
+ mPipRecentsOverlayManager.onRecentsPaused();
+ }
+
+ @Override
protected void onStop() {
super.onStop();
- mPipManager.onRecentsStopped();
mIgnoreAltTabRelease = false;
// Notify that recents is now hidden
EventBus.getDefault().send(new RecentsVisibilityChangedEvent(this, false));
@@ -480,25 +511,13 @@
private void updatePipUI() {
if (mPipManager.isPipShown()) {
- mPipControlsView.setAlpha(0);
- mPipControlsView.setVisibility(View.VISIBLE);
- mPipShadeView.setVisibility(View.INVISIBLE);
- mPipControlsView.setOnChildFocusChangeListener(new View.OnFocusChangeListener() {
- @Override
- public void onFocusChange(View v, boolean hasFocus) {
- mPipManager.onPipViewFocusChangedInRecents(hasFocus);
- if (hasFocus) {
- mPipControlsViewFadeInAnimator.start();
- } else {
- mPipControlsViewFadeOutAnimator.start();
- }
- mPipShadeView.setVisibility(hasFocus ? View.VISIBLE : View.INVISIBLE);
- }
- });
- mPipShadeView.setVisibility(View.GONE);
+ mPipView.setVisibility(View.VISIBLE);
+ mPipView.setOnFocusChangeListener(mPipViewFocusChangeListener);
+ mPipView.requestFocus();
} else {
- mPipControlsView.setVisibility(View.GONE);
- mPipShadeView.setVisibility(View.GONE);
+ mPipView.setVisibility(View.GONE);
+ mPipRecentsOverlayManager.removePipRecentsOverlayView();
+ mRecentsFocusAnimationHolder.reset();
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/tv/animations/FocusAnimationHolder.java b/packages/SystemUI/src/com/android/systemui/recents/tv/animations/FocusAnimationHolder.java
new file mode 100644
index 0000000..864540c
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/tv/animations/FocusAnimationHolder.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.systemui.recents.tv.animations;
+
+import android.content.res.Resources;
+import android.view.View;
+
+import com.android.systemui.Interpolators;
+import com.android.systemui.R;
+import com.android.systemui.recents.tv.views.TaskCardView;
+
+/**
+ * Collections of Recents row's animation depending on the PIP's focus.
+ */
+public class FocusAnimationHolder {
+ private final float DIM_ALPHA = 0.5f;
+
+ private View mRecentsRowView;
+ private int mCardYDelta;
+ private long mDuration;
+
+ public FocusAnimationHolder(View recentsRowView) {
+ mRecentsRowView = recentsRowView;
+
+ Resources res = recentsRowView.getResources();
+ mCardYDelta = res.getDimensionPixelOffset(R.dimen.recents_tv_dismiss_shift_down);
+ mDuration = res.getInteger(R.integer.recents_tv_pip_focus_anim_duration);
+ }
+
+ public void startFocusGainAnimation() {
+ mRecentsRowView.animate()
+ .setDuration(mDuration)
+ .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
+ .alpha(1f)
+ .translationY(0);
+ }
+
+ public void startFocusLoseAnimation() {
+ mRecentsRowView.animate()
+ .setDuration(mDuration)
+ .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
+ .alpha(DIM_ALPHA)
+ .translationY(mCardYDelta);
+ }
+
+ public void reset() {
+ mRecentsRowView.setTransitionAlpha(1f);
+ mRecentsRowView.setTranslationY(0);
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/tv/views/RecentsTvTransitionHelper.java b/packages/SystemUI/src/com/android/systemui/recents/tv/views/RecentsTvTransitionHelper.java
index bd3143f..a69f8a2 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/tv/views/RecentsTvTransitionHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/tv/views/RecentsTvTransitionHelper.java
@@ -89,7 +89,7 @@
private void startTaskActivity(TaskStack stack, Task task, @Nullable TaskCardView taskView,
ActivityOptions opts,final ActivityOptions.OnAnimationStartedListener animStartedListener) {
SystemServicesProxy ssp = Recents.getSystemServices();
- if (ssp.startActivityFromRecents(mContext, task.key.id, task.title, opts)) {
+ if (ssp.startActivityFromRecents(mContext, task.key, task.title, opts)) {
// Keep track of the index of the task launch
int taskIndexFromFront = 0;
int taskIndex = stack.indexOfStackTask(task);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/tv/views/RecentsTvView.java b/packages/SystemUI/src/com/android/systemui/recents/tv/views/RecentsTvView.java
index 3d5176f..d966614 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/tv/views/RecentsTvView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/tv/views/RecentsTvView.java
@@ -109,7 +109,7 @@
Task task = mTaskStackHorizontalView.getFocusedTask();
if (task != null) {
SystemServicesProxy ssp = Recents.getSystemServices();
- ssp.startActivityFromRecents(getContext(), task.key.id, task.title, null);
+ ssp.startActivityFromRecents(getContext(), task.key, task.title, null);
return true;
}
}
@@ -123,7 +123,7 @@
Task task = stack.getLaunchTarget();
if (task != null) {
SystemServicesProxy ssp = Recents.getSystemServices();
- ssp.startActivityFromRecents(getContext(), task.key.id, task.title, null);
+ ssp.startActivityFromRecents(getContext(), task.key, task.title, null);
return true;
}
}
@@ -140,7 +140,7 @@
TaskCardView tv = taskViews.get(j);
if (tv.getTask() == task) {
SystemServicesProxy ssp = Recents.getSystemServices();
- ssp.startActivityFromRecents(getContext(), task.key.id, task.title, null);
+ ssp.startActivityFromRecents(getContext(), task.key, task.title, null);
return true;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/tv/views/TaskStackHorizontalGridView.java b/packages/SystemUI/src/com/android/systemui/recents/tv/views/TaskStackHorizontalGridView.java
index 3d0e75a..5eb9fda 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/tv/views/TaskStackHorizontalGridView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/tv/views/TaskStackHorizontalGridView.java
@@ -158,6 +158,11 @@
}
@Override
+ public void onStackTasksRemoved(TaskStack stack) {
+ // Do nothing
+ }
+
+ @Override
public void onStackTasksUpdated(TaskStack stack) {
// Do nothing
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionHelper.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionHelper.java
index 98616f4..9eec2ce 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionHelper.java
@@ -28,11 +28,13 @@
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
+import android.graphics.Color;
import android.graphics.Rect;
import android.os.Bundle;
import android.os.Handler;
import android.os.IRemoteCallback;
import android.os.RemoteException;
+import android.util.Log;
import android.view.AppTransitionAnimationSpec;
import android.view.IAppTransitionAnimationSpecsFuture;
@@ -186,7 +188,7 @@
ActivityOptions opts, IAppTransitionAnimationSpecsFuture transitionFuture,
final ActivityOptions.OnAnimationStartedListener animStartedListener) {
SystemServicesProxy ssp = Recents.getSystemServices();
- if (ssp.startActivityFromRecents(mContext, task.key.id, task.title, opts)) {
+ if (ssp.startActivityFromRecents(mContext, task.key, task.title, opts)) {
// Keep track of the index of the task launch
int taskIndexFromFront = 0;
int taskIndex = stack.indexOfStackTask(task);
@@ -252,12 +254,13 @@
/**
* Composes the transition spec when docking a task, which includes a full task bitmap.
*/
- public List<AppTransitionAnimationSpec> composeDockAnimationSpec(
- TaskView taskView, Rect transform) {
- TaskViewTransform viewTransform = new TaskViewTransform();
- viewTransform.fillIn(taskView);
- return Collections.singletonList(new AppTransitionAnimationSpec(taskView.getTask().key.id,
- RecentsTransitionHelper.composeTaskBitmap(taskView, viewTransform), transform));
+ public List<AppTransitionAnimationSpec> composeDockAnimationSpec(TaskView taskView,
+ Rect bounds) {
+ mTmpTransform.fillIn(taskView);
+ Task task = taskView.getTask();
+ Bitmap thumbnail = RecentsTransitionHelper.composeTaskBitmap(taskView, mTmpTransform);
+ return Collections.singletonList(new AppTransitionAnimationSpec(task.key.id, thumbnail,
+ bounds));
}
/**
@@ -336,18 +339,27 @@
float scale = transform.scale;
int fromWidth = (int) (transform.rect.width() * scale);
int fromHeight = (int) (transform.rect.height() * scale);
- Bitmap b = Bitmap.createBitmap(fromWidth, fromHeight,
- Bitmap.Config.ARGB_8888);
+ if (fromWidth == 0 || fromHeight == 0) {
+ Log.e(TAG, "Could not compose thumbnail for task: " + taskView.getTask() +
+ " at transform: " + transform);
- if (RecentsDebugFlags.Static.EnableTransitionThumbnailDebugMode) {
- b.eraseColor(0xFFff0000);
+ Bitmap b = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888);
+ b.eraseColor(Color.TRANSPARENT);
+ return b;
} else {
- Canvas c = new Canvas(b);
- c.scale(scale, scale);
- taskView.draw(c);
- c.setBitmap(null);
+ Bitmap b = Bitmap.createBitmap(fromWidth, fromHeight,
+ Bitmap.Config.ARGB_8888);
+
+ if (RecentsDebugFlags.Static.EnableTransitionThumbnailDebugMode) {
+ b.eraseColor(0xFFff0000);
+ } else {
+ Canvas c = new Canvas(b);
+ c.scale(scale, scale);
+ taskView.draw(c);
+ c.setBitmap(null);
+ }
+ return b.createAshmemBitmap();
}
- return b.createAshmemBitmap();
}
private static Bitmap composeHeaderBitmap(TaskView taskView,
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
index a1ba493..e0d0486 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
@@ -58,10 +58,10 @@
import com.android.systemui.recents.events.activity.HideStackActionButtonEvent;
import com.android.systemui.recents.events.activity.LaunchTaskEvent;
import com.android.systemui.recents.events.activity.ShowStackActionButtonEvent;
+import com.android.systemui.recents.events.ui.AllTaskViewsDismissedEvent;
+import com.android.systemui.recents.events.ui.DismissAllTaskViewsEvent;
import com.android.systemui.recents.events.ui.DraggingInRecentsEndedEvent;
import com.android.systemui.recents.events.ui.DraggingInRecentsEvent;
-import com.android.systemui.recents.events.ui.ResetBackgroundScrimEvent;
-import com.android.systemui.recents.events.ui.UpdateBackgroundScrimEvent;
import com.android.systemui.recents.events.ui.dragndrop.DragDropTargetChangedEvent;
import com.android.systemui.recents.events.ui.dragndrop.DragEndEvent;
import com.android.systemui.recents.events.ui.dragndrop.DragStartEvent;
@@ -87,6 +87,9 @@
private static final int DEFAULT_UPDATE_SCRIM_DURATION = 200;
private static final float DEFAULT_SCRIM_ALPHA = 0.33f;
+ private static final int SHOW_STACK_ACTION_BUTTON_DURATION = 150;
+ private static final int HIDE_STACK_ACTION_BUTTON_DURATION = 100;
+
private TaskStack mStack;
private TaskStackView mTaskStackView;
private TextView mStackActionButton;
@@ -99,7 +102,8 @@
private Rect mSystemInsets = new Rect();
private int mDividerSize;
- private ColorDrawable mBackgroundScrim = new ColorDrawable(Color.BLACK);
+ private Drawable mBackgroundScrim = new ColorDrawable(
+ Color.argb((int) (DEFAULT_SCRIM_ALPHA * 255), 0, 0, 0)).mutate();
private Animator mBackgroundScrimAnimator;
private RecentsTransitionHelper mTransitionHelper;
@@ -135,10 +139,11 @@
R.dimen.recents_task_view_rounded_corners_radius);
mStackActionButton = (TextView) inflater.inflate(R.layout.recents_stack_action_button,
this, false);
+ mStackActionButton.forceHasOverlappingRendering(false);
mStackActionButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
- // TODO: To be implemented
+ EventBus.getDefault().send(new DismissAllTaskViewsEvent());
}
});
addView(mStackActionButton);
@@ -152,8 +157,6 @@
}
mEmptyView = (TextView) inflater.inflate(R.layout.recents_empty, this, false);
addView(mEmptyView);
-
- setBackground(mBackgroundScrim);
}
/**
@@ -179,14 +182,14 @@
if (isResumingFromVisible) {
// If we are already visible, then restore the background scrim
- animateBackgroundScrim(DEFAULT_SCRIM_ALPHA, DEFAULT_UPDATE_SCRIM_DURATION);
+ animateBackgroundScrim(1f, DEFAULT_UPDATE_SCRIM_DURATION);
} else {
// If we are already occluded by the app, then set the final background scrim alpha now.
// Otherwise, defer until the enter animation completes to animate the scrim alpha with
// the tasks for the home animation.
- if (launchState.launchedWhileDocking || launchState.launchedFromApp
+ if (launchState.launchedViaDockGesture || launchState.launchedFromApp
|| isTaskStackEmpty) {
- mBackgroundScrim.setAlpha((int) (DEFAULT_SCRIM_ALPHA * 255));
+ mBackgroundScrim.setAlpha(255);
} else {
mBackgroundScrim.setAlpha(0);
}
@@ -215,6 +218,13 @@
return mStack;
}
+ /*
+ * Returns the window background scrim.
+ */
+ public Drawable getBackgroundScrim() {
+ return mBackgroundScrim;
+ }
+
/**
* Returns whether the last task launched was in the freeform stack or not.
*/
@@ -333,10 +343,10 @@
if (RecentsDebugFlags.Static.EnableStackActionButton) {
// Measure the stack action button within the constraints of the space above the stack
- Rect actionButtonRect = mTaskStackView.mLayoutAlgorithm.mStackActionButtonRect;
+ Rect buttonBounds = mTaskStackView.mLayoutAlgorithm.mStackActionButtonRect;
measureChild(mStackActionButton,
- MeasureSpec.makeMeasureSpec(actionButtonRect.width(), MeasureSpec.AT_MOST),
- MeasureSpec.makeMeasureSpec(actionButtonRect.height(), MeasureSpec.AT_MOST));
+ MeasureSpec.makeMeasureSpec(buttonBounds.width(), MeasureSpec.AT_MOST),
+ MeasureSpec.makeMeasureSpec(buttonBounds.height(), MeasureSpec.AT_MOST));
}
setMeasuredDimension(width, height);
@@ -365,16 +375,9 @@
if (RecentsDebugFlags.Static.EnableStackActionButton) {
// Layout the stack action button such that its drawable is start-aligned with the
// stack, vertically centered in the available space above the stack
- Rect actionButtonRect = mTaskStackView.mLayoutAlgorithm.mStackActionButtonRect;
- int buttonLeft = isLayoutRtl()
- ? actionButtonRect.right + mStackActionButton.getPaddingStart()
- - mStackActionButton.getMeasuredWidth()
- : actionButtonRect.left - mStackActionButton.getPaddingStart();
- int buttonTop = actionButtonRect.top +
- (actionButtonRect.height() - mStackActionButton.getMeasuredHeight()) / 2;
- mStackActionButton.layout(buttonLeft, buttonTop,
- buttonLeft + mStackActionButton.getMeasuredWidth(),
- buttonTop + mStackActionButton.getMeasuredHeight());
+ Rect buttonBounds = getStackActionButtonBoundsFromStackLayout();
+ mStackActionButton.layout(buttonBounds.left, buttonBounds.top, buttonBounds.right,
+ buttonBounds.bottom);
}
if (mAwaitingFirstLayout) {
@@ -468,6 +471,17 @@
false /* isDefaultDockState */, -1, true /* animateAlpha */,
true /* animateBounds */);
}
+ if (mStackActionButton != null) {
+ event.addPostAnimationCallback(new Runnable() {
+ @Override
+ public void run() {
+ // Move the clear all button to its new position
+ Rect buttonBounds = getStackActionButtonBoundsFromStackLayout();
+ mStackActionButton.setLeftTopRightBottom(buttonBounds.left, buttonBounds.top,
+ buttonBounds.right, buttonBounds.bottom);
+ }
+ });
+ }
}
public final void onBusEvent(final DragEndEvent event) {
@@ -564,19 +578,23 @@
public final void onBusEvent(EnterRecentsWindowAnimationCompletedEvent event) {
RecentsActivityLaunchState launchState = Recents.getConfiguration().getLaunchState();
- if (!launchState.launchedWhileDocking && !launchState.launchedFromApp
+ if (!launchState.launchedViaDockGesture && !launchState.launchedFromApp
&& mStack.getTaskCount() > 0) {
- animateBackgroundScrim(DEFAULT_SCRIM_ALPHA,
+ animateBackgroundScrim(1f,
TaskStackAnimationHelper.ENTER_FROM_HOME_TRANSLATION_DURATION);
}
}
- public final void onBusEvent(UpdateBackgroundScrimEvent event) {
- animateBackgroundScrim(event.alpha, DEFAULT_UPDATE_SCRIM_DURATION);
+ public final void onBusEvent(AllTaskViewsDismissedEvent event) {
+ hideStackActionButton(HIDE_STACK_ACTION_BUTTON_DURATION, true /* translate */);
}
- public final void onBusEvent(ResetBackgroundScrimEvent event) {
- animateBackgroundScrim(DEFAULT_SCRIM_ALPHA, DEFAULT_UPDATE_SCRIM_DURATION);
+ public final void onBusEvent(DismissAllTaskViewsEvent event) {
+ SystemServicesProxy ssp = Recents.getSystemServices();
+ if (!ssp.hasDockedTask()) {
+ // Animate the background away only if we are dismissing Recents to home
+ animateBackgroundScrim(0f, DEFAULT_UPDATE_SCRIM_DURATION);
+ }
}
public final void onBusEvent(ShowStackActionButtonEvent event) {
@@ -584,7 +602,7 @@
return;
}
- showStackActionButton(150, event.translate);
+ showStackActionButton(SHOW_STACK_ACTION_BUTTON_DURATION, event.translate);
}
public final void onBusEvent(HideStackActionButtonEvent event) {
@@ -592,7 +610,7 @@
return;
}
- hideStackActionButton(100, true /* translate */);
+ hideStackActionButton(HIDE_STACK_ACTION_BUTTON_DURATION, true /* translate */);
}
/**
@@ -623,7 +641,6 @@
.alpha(1f)
.setDuration(duration)
.setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
- .withLayer()
.start();
}
});
@@ -669,7 +686,6 @@
postAnimationTrigger.decrement();
}
})
- .withLayer()
.start();
postAnimationTrigger.increment();
}
@@ -713,13 +729,31 @@
*/
private void animateBackgroundScrim(float alpha, int duration) {
Utilities.cancelAnimationWithoutCallbacks(mBackgroundScrimAnimator);
- int alphaInt = (int) (alpha * 255);
+ // Calculate the absolute alpha to animate from
+ int fromAlpha = (int) ((mBackgroundScrim.getAlpha() / (DEFAULT_SCRIM_ALPHA * 255)) * 255);
+ int toAlpha = (int) (alpha * 255);
mBackgroundScrimAnimator = ObjectAnimator.ofInt(mBackgroundScrim, Utilities.DRAWABLE_ALPHA,
- mBackgroundScrim.getAlpha(), alphaInt);
+ fromAlpha, toAlpha);
mBackgroundScrimAnimator.setDuration(duration);
- mBackgroundScrimAnimator.setInterpolator(alphaInt > mBackgroundScrim.getAlpha()
- ? Interpolators.ALPHA_OUT
- : Interpolators.ALPHA_IN);
+ mBackgroundScrimAnimator.setInterpolator(toAlpha > fromAlpha
+ ? Interpolators.ALPHA_IN
+ : Interpolators.ALPHA_OUT);
mBackgroundScrimAnimator.start();
}
+
+ /**
+ * @return the bounds of the stack action button.
+ */
+ private Rect getStackActionButtonBoundsFromStackLayout() {
+ Rect actionButtonRect = new Rect(mTaskStackView.mLayoutAlgorithm.mStackActionButtonRect);
+ int left = isLayoutRtl()
+ ? actionButtonRect.left - mStackActionButton.getPaddingLeft()
+ : actionButtonRect.right + mStackActionButton.getPaddingRight()
+ - mStackActionButton.getMeasuredWidth();
+ int top = actionButtonRect.top +
+ (actionButtonRect.height() - mStackActionButton.getMeasuredHeight()) / 2;
+ actionButtonRect.set(left, top, left + mStackActionButton.getMeasuredWidth(),
+ top + mStackActionButton.getMeasuredHeight());
+ return actionButtonRect;
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/SystemBarScrimViews.java b/packages/SystemUI/src/com/android/systemui/recents/views/SystemBarScrimViews.java
index 9c8189a..07a1d4e 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/SystemBarScrimViews.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/SystemBarScrimViews.java
@@ -16,39 +16,58 @@
package com.android.systemui.recents.views;
-import android.app.Activity;
import android.content.Context;
import android.view.View;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
+import com.android.systemui.recents.Recents;
+import com.android.systemui.recents.RecentsActivity;
+import com.android.systemui.recents.events.activity.ConfigurationChangedEvent;
import com.android.systemui.recents.events.activity.DismissRecentsToHomeAnimationStarted;
import com.android.systemui.recents.events.activity.EnterRecentsWindowAnimationCompletedEvent;
+import com.android.systemui.recents.events.ui.DismissAllTaskViewsEvent;
+import com.android.systemui.recents.events.activity.MultiWindowStateChangedEvent;
+import com.android.systemui.recents.misc.SystemServicesProxy;
/** Manages the scrims for the various system bars. */
public class SystemBarScrimViews {
- Context mContext;
+ private static final int DEFAULT_ANIMATION_DURATION = 150;
- View mNavBarScrimView;
+ private Context mContext;
- boolean mHasNavBarScrim;
- boolean mShouldAnimateNavBarScrim;
+ private View mNavBarScrimView;
- int mNavBarScrimEnterDuration;
+ private boolean mHasNavBarScrim;
+ private boolean mShouldAnimateNavBarScrim;
- public SystemBarScrimViews(Activity activity) {
+ private int mNavBarScrimEnterDuration;
+
+ public SystemBarScrimViews(RecentsActivity activity) {
mContext = activity;
mNavBarScrimView = activity.findViewById(R.id.nav_bar_scrim);
+ mNavBarScrimView.forceHasOverlappingRendering(false);
mNavBarScrimEnterDuration = activity.getResources().getInteger(
R.integer.recents_nav_bar_scrim_enter_duration);
}
/**
+ * Updates the nav bar scrim.
+ */
+ public void updateNavBarScrim(boolean animateNavBarScrim, boolean hasStackTasks,
+ AnimationProps animation) {
+ prepareEnterRecentsAnimation(isNavBarScrimRequired(hasStackTasks), animateNavBarScrim);
+ if (animateNavBarScrim && animation != null) {
+ animateNavBarScrimVisibility(true, animation);
+ }
+ }
+
+ /**
* Prepares the scrim views for animating when entering Recents. This will be called before
* the first draw, unless we are updating the scrim on configuration change.
*/
- public void prepareEnterRecentsAnimation(boolean hasNavBarScrim, boolean animateNavBarScrim) {
+ private void prepareEnterRecentsAnimation(boolean hasNavBarScrim, boolean animateNavBarScrim) {
mHasNavBarScrim = hasNavBarScrim;
mShouldAnimateNavBarScrim = animateNavBarScrim;
@@ -59,7 +78,7 @@
/**
* Animates the nav bar scrim visibility.
*/
- public void animateNavBarScrimVisibility(boolean visible, AnimationProps animation) {
+ private void animateNavBarScrimVisibility(boolean visible, AnimationProps animation) {
int toY = 0;
if (visible) {
mNavBarScrimView.setVisibility(View.VISIBLE);
@@ -78,6 +97,14 @@
}
}
+ /**
+ * @return Whether to show the nav bar scrim.
+ */
+ private boolean isNavBarScrimRequired(boolean hasStackTasks) {
+ SystemServicesProxy ssp = Recents.getSystemServices();
+ return hasStackTasks && !ssp.hasTransposedNavBar() && !ssp.hasDockedTask();
+ }
+
/**** EventBus events ****/
/**
@@ -100,11 +127,48 @@
*/
public final void onBusEvent(DismissRecentsToHomeAnimationStarted event) {
if (mHasNavBarScrim) {
- AnimationProps animation = new AnimationProps()
- .setDuration(AnimationProps.BOUNDS,
- TaskStackAnimationHelper.EXIT_TO_HOME_TRANSLATION_DURATION)
- .setInterpolator(AnimationProps.BOUNDS, Interpolators.FAST_OUT_SLOW_IN);
+ AnimationProps animation = createBoundsAnimation(
+ TaskStackAnimationHelper.EXIT_TO_HOME_TRANSLATION_DURATION);
animateNavBarScrimVisibility(false, animation);
}
}
+
+ public final void onBusEvent(DismissAllTaskViewsEvent event) {
+ if (mHasNavBarScrim) {
+ AnimationProps animation = createBoundsAnimation(
+ TaskStackAnimationHelper.EXIT_TO_HOME_TRANSLATION_DURATION);
+ animateNavBarScrimVisibility(false, animation);
+ }
+ }
+
+ public final void onBusEvent(ConfigurationChangedEvent event) {
+ animateScrimToCurrentNavBarState(event.hasStackTasks);
+ }
+
+ public final void onBusEvent(MultiWindowStateChangedEvent event) {
+ animateScrimToCurrentNavBarState(event.hasStackTasks);
+ }
+
+ /**
+ * Animates the scrim to match the state of the current nav bar.
+ */
+ private void animateScrimToCurrentNavBarState(boolean hasStackTasks) {
+ boolean hasNavBarScrim = isNavBarScrimRequired(hasStackTasks);
+ if (mHasNavBarScrim != hasNavBarScrim) {
+ AnimationProps animation = hasNavBarScrim
+ ? createBoundsAnimation(DEFAULT_ANIMATION_DURATION)
+ : AnimationProps.IMMEDIATE;
+ animateNavBarScrimVisibility(hasNavBarScrim, animation);
+ }
+ mHasNavBarScrim = hasNavBarScrim;
+ }
+
+ /**
+ * @return a default animation to aniamte the bounds of the scrim.
+ */
+ private AnimationProps createBoundsAnimation(int duration) {
+ return new AnimationProps()
+ .setDuration(AnimationProps.BOUNDS, duration)
+ .setInterpolator(AnimationProps.BOUNDS, Interpolators.FAST_OUT_SLOW_IN);
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackAnimationHelper.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackAnimationHelper.java
index 1c7d609..1c433d8 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackAnimationHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackAnimationHelper.java
@@ -20,7 +20,6 @@
import android.animation.AnimatorListenerAdapter;
import android.content.Context;
import android.content.res.Resources;
-import android.graphics.RectF;
import android.util.Log;
import android.view.View;
import android.view.animation.Interpolator;
@@ -32,6 +31,7 @@
import com.android.systemui.recents.RecentsActivityLaunchState;
import com.android.systemui.recents.RecentsConfiguration;
import com.android.systemui.recents.misc.ReferenceCountedTrigger;
+import com.android.systemui.recents.misc.Utilities;
import com.android.systemui.recents.model.Task;
import com.android.systemui.recents.model.TaskStack;
@@ -152,30 +152,26 @@
if (hideTask) {
tv.setVisibility(View.INVISIBLE);
- } else if (launchState.launchedFromApp && !launchState.launchedWhileDocking) {
+ } else if (launchState.launchedFromApp && !launchState.launchedViaDockGesture) {
if (task.isLaunchTarget) {
tv.onPrepareLaunchTargetForEnterAnimation();
} else if (currentTaskOccludesLaunchTarget) {
// Move the task view slightly lower so we can animate it in
- RectF bounds = new RectF(mTmpTransform.rect);
- bounds.offset(0, taskViewAffiliateGroupEnterOffset);
+ mTmpTransform.rect.offset(0, taskViewAffiliateGroupEnterOffset);
+ mTmpTransform.alpha = 0f;
+ mStackView.updateTaskViewToTransform(tv, mTmpTransform,
+ AnimationProps.IMMEDIATE);
tv.setClipViewInStack(false);
- tv.setAlpha(0f);
- tv.setLeftTopRightBottom((int) bounds.left, (int) bounds.top,
- (int) bounds.right, (int) bounds.bottom);
}
} else if (launchState.launchedFromHome) {
// Move the task view off screen (below) so we can animate it in
- RectF bounds = new RectF(mTmpTransform.rect);
- bounds.offset(0, offscreenYOffset);
- tv.setAlpha(0f);
- tv.setLeftTopRightBottom((int) bounds.left, (int) bounds.top, (int) bounds.right,
- (int) bounds.bottom);
- } else if (launchState.launchedWhileDocking) {
- RectF bounds = new RectF(mTmpTransform.rect);
- bounds.offset(0, launchedWhileDockingOffset);
- tv.setLeftTopRightBottom((int) bounds.left, (int) bounds.top, (int) bounds.right,
- (int) bounds.bottom);
+ mTmpTransform.rect.offset(0, offscreenYOffset);
+ mTmpTransform.alpha = 0f;
+ mStackView.updateTaskViewToTransform(tv, mTmpTransform, AnimationProps.IMMEDIATE);
+ } else if (launchState.launchedViaDockGesture) {
+ mTmpTransform.rect.offset(0, launchedWhileDockingOffset);
+ mTmpTransform.alpha = 0f;
+ mStackView.updateTaskViewToTransform(tv, mTmpTransform, AnimationProps.IMMEDIATE);
}
}
}
@@ -223,7 +219,7 @@
stackLayout.getStackTransform(task, stackScroller.getStackScroll(), mTmpTransform,
null);
- if (launchState.launchedFromApp && !launchState.launchedWhileDocking) {
+ if (launchState.launchedFromApp && !launchState.launchedViaDockGesture) {
if (task.isLaunchTarget) {
tv.onStartLaunchTargetEnterAnimation(mTmpTransform,
taskViewEnterFromAppDuration, mStackView.mScreenPinningEnabled,
@@ -262,7 +258,7 @@
if (i == taskViewCount - 1) {
tv.onStartFrontTaskEnterAnimation(mStackView.mScreenPinningEnabled);
}
- } else if (launchState.launchedWhileDocking) {
+ } else if (launchState.launchedViaDockGesture) {
// Animate the tasks up
AnimationProps taskAnimation = new AnimationProps()
.setDuration(AnimationProps.BOUNDS, (int) (ENTER_WHILE_DOCKING_DURATION +
@@ -282,7 +278,6 @@
public void startExitToHomeAnimation(boolean animated,
ReferenceCountedTrigger postAnimationTrigger) {
TaskStackLayoutAlgorithm stackLayout = mStackView.getStackAlgorithm();
- TaskStackViewScroller stackScroller = mStackView.getScroller();
TaskStack stack = mStackView.getStack();
// Break early if there are no tasks
@@ -318,8 +313,7 @@
taskAnimation = AnimationProps.IMMEDIATE;
}
- stackLayout.getStackTransform(task, stackScroller.getStackScroll(), mTmpTransform,
- null);
+ mTmpTransform.fillIn(tv);
mTmpTransform.alpha = 0f;
mTmpTransform.rect.offset(0, offscreenYOffset);
mStackView.updateTaskViewToTransform(tv, mTmpTransform, taskAnimation);
@@ -333,8 +327,6 @@
public void startLaunchTaskAnimation(TaskView launchingTaskView, boolean screenPinningRequested,
final ReferenceCountedTrigger postAnimationTrigger) {
Resources res = mStackView.getResources();
- TaskStackLayoutAlgorithm stackLayout = mStackView.getStackAlgorithm();
- TaskStackViewScroller stackScroller = mStackView.getScroller();
int taskViewExitToAppDuration = res.getInteger(
R.integer.recents_task_exit_to_app_duration);
@@ -367,8 +359,7 @@
postAnimationTrigger.decrementOnAnimationEnd());
postAnimationTrigger.increment();
- stackLayout.getStackTransform(task, stackScroller.getStackScroll(), mTmpTransform,
- null);
+ mTmpTransform.fillIn(tv);
mTmpTransform.alpha = 0f;
mTmpTransform.rect.offset(0, taskViewAffiliateGroupEnterOffset);
mStackView.updateTaskViewToTransform(tv, mTmpTransform, taskAnimation);
@@ -379,16 +370,14 @@
/**
* Starts the delete animation for the specified {@link TaskView}.
*/
- public void startDeleteTaskAnimation(Task deleteTask, final TaskView deleteTaskView,
+ public void startDeleteTaskAnimation(final TaskView deleteTaskView,
final ReferenceCountedTrigger postAnimationTrigger) {
Resources res = mStackView.getResources();
TaskStackLayoutAlgorithm stackLayout = mStackView.getStackAlgorithm();
- TaskStackViewScroller stackScroller = mStackView.getScroller();
int taskViewRemoveAnimDuration = res.getInteger(
R.integer.recents_animate_task_view_remove_duration);
- int taskViewRemoveAnimTranslationXPx = res.getDimensionPixelSize(
- R.dimen.recents_task_view_remove_anim_translation_x);
+ int offscreenXOffset = mStackView.getMeasuredWidth() - stackLayout.mTaskRect.left;
// Disabling clipping with the stack while the view is animating away, this will get
// restored when the task is next picked up from the view pool
@@ -404,14 +393,58 @@
});
postAnimationTrigger.increment();
- stackLayout.getStackTransform(deleteTask, stackScroller.getStackScroll(), mTmpTransform,
- null);
+ mTmpTransform.fillIn(deleteTaskView);
mTmpTransform.alpha = 0f;
- mTmpTransform.rect.offset(taskViewRemoveAnimTranslationXPx, 0);
+ mTmpTransform.rect.offset(offscreenXOffset, 0);
mStackView.updateTaskViewToTransform(deleteTaskView, mTmpTransform, taskAnimation);
}
/**
+ * Starts the delete animation for all the {@link TaskView}s.
+ */
+ public void startDeleteAllTasksAnimation(final List<TaskView> taskViews,
+ final ReferenceCountedTrigger postAnimationTrigger) {
+ Resources res = mStackView.getResources();
+ TaskStackLayoutAlgorithm stackLayout = mStackView.getStackAlgorithm();
+
+ int taskViewRemoveAnimDuration = res.getInteger(
+ R.integer.recents_animate_task_views_remove_all_duration);
+ int offscreenXOffset = mStackView.getMeasuredWidth() - stackLayout.mTaskRect.left;
+
+ int taskViewCount = taskViews.size();
+ int startDelayMax = 125;
+
+ for (int i = taskViewCount - 1; i >= 0; i--) {
+ TaskView tv = taskViews.get(i);
+ int indexFromFront = taskViewCount - i - 1;
+ float x = Interpolators.ACCELERATE.getInterpolation((float) indexFromFront /
+ taskViewCount);
+ int startDelay = (int) Utilities.mapRange(x, 0, startDelayMax);
+
+ // Disabling clipping with the stack while the view is animating away
+ tv.setClipViewInStack(false);
+
+ // Compose the new animation and transform and star the animation
+ AnimationProps taskAnimation = new AnimationProps(startDelay,
+ taskViewRemoveAnimDuration, Interpolators.FAST_OUT_LINEAR_IN,
+ new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ postAnimationTrigger.decrement();
+
+ // Re-enable clipping with the stack (we will reuse this view)
+ tv.setClipViewInStack(true);
+ }
+ });
+ postAnimationTrigger.increment();
+
+ mTmpTransform.fillIn(tv);
+ mTmpTransform.rect.offset(offscreenXOffset, 0);
+ mStackView.updateTaskViewToTransform(tv, mTmpTransform, taskAnimation);
+ }
+ }
+
+ /**
* Starts the animation to focus the next {@link TaskView} when paging through recents.
*
* @return whether or not this will trigger a scroll in the stack
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java
index 8a1727a..9eab0f6 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java
@@ -537,11 +537,13 @@
} else {
mInitialScrollP = Utilities.clamp(launchTaskIndex - 1, mMinScrollP, mMaxScrollP);
}
+ mInitialNormX = null;
} else if (!ssp.hasFreeformWorkspaceSupport() && mNumStackTasks == 1) {
// If there is one stack task, ignore the min/max/initial scroll positions
mMinScrollP = 0;
mMaxScrollP = 0;
mInitialScrollP = 0;
+ mInitialNormX = null;
} else {
// Set the max scroll to be the point where the front most task is visible with the
// stack bottom offset
@@ -552,20 +554,22 @@
mMaxScrollP = Math.max(mMinScrollP, (mNumStackTasks - 1) -
Math.max(0, mUnfocusedRange.getAbsoluteX(maxBottomNormX)));
boolean scrollToFront = launchState.launchedFromHome ||
- launchState.launchedFromAppDocked;
+ launchState.launchedViaDockGesture;
if (scrollToFront) {
mInitialScrollP = Utilities.clamp(launchTaskIndex, mMinScrollP, mMaxScrollP);
mInitialNormX = null;
} else {
- float normX = getNormalizedXFromUnfocusedY(mInitialTopOffset, FROM_TOP);
- mInitialScrollP = Math.max(mMinScrollP, Math.min(mMaxScrollP, (mNumStackTasks - 2)) -
- Math.max(0, mUnfocusedRange.getAbsoluteX(normX)));
+ // We are overriding the initial two task positions, so set the initial scroll
+ // position to match the second task (aka focused task) position
+ float initialTopNormX = getNormalizedXFromUnfocusedY(mInitialTopOffset, FROM_TOP);
+ mInitialScrollP = Math.max(mMinScrollP, Math.min(mMaxScrollP, (mNumStackTasks - 2))
+ - Math.max(0, mUnfocusedRange.getAbsoluteX(initialTopNormX)));
// Set the initial scroll to the predefined state (which differs from the stack)
mInitialNormX = new float[] {
getNormalizedXFromUnfocusedY(mSystemInsets.bottom + mInitialBottomOffset,
FROM_BOTTOM),
- normX
+ initialTopNormX
};
}
}
@@ -801,8 +805,9 @@
public TaskViewTransform getStackTransformScreenCoordinates(Task task, float stackScroll,
TaskViewTransform transformOut, TaskViewTransform frontTransform) {
Rect windowRect = Recents.getSystemServices().getWindowRect();
- TaskViewTransform transform = getStackTransform(task, stackScroll, transformOut,
- frontTransform);
+ TaskViewTransform transform = getStackTransform(task, stackScroll, mFocusState,
+ transformOut, frontTransform, true /* forceUpdate */,
+ false /* ignoreTaskOverrides */);
transform.rect.offset(windowRect.left, windowRect.top);
return transform;
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
index 9032871..5416a48 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
@@ -28,6 +28,7 @@
import android.content.res.Resources;
import android.graphics.Canvas;
import android.graphics.Rect;
+import android.graphics.RectF;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.GradientDrawable;
import android.os.Bundle;
@@ -60,8 +61,8 @@
import com.android.systemui.recents.events.activity.DismissRecentsToHomeAnimationStarted;
import com.android.systemui.recents.events.activity.EnterRecentsTaskStackAnimationCompletedEvent;
import com.android.systemui.recents.events.activity.EnterRecentsWindowAnimationCompletedEvent;
-import com.android.systemui.recents.events.activity.HideStackActionButtonEvent;
import com.android.systemui.recents.events.activity.HideRecentsEvent;
+import com.android.systemui.recents.events.activity.HideStackActionButtonEvent;
import com.android.systemui.recents.events.activity.IterateRecentsEvent;
import com.android.systemui.recents.events.activity.LaunchNextTaskRequestEvent;
import com.android.systemui.recents.events.activity.LaunchTaskEvent;
@@ -71,6 +72,7 @@
import com.android.systemui.recents.events.activity.ShowStackActionButtonEvent;
import com.android.systemui.recents.events.ui.AllTaskViewsDismissedEvent;
import com.android.systemui.recents.events.ui.DeleteTaskDataEvent;
+import com.android.systemui.recents.events.ui.DismissAllTaskViewsEvent;
import com.android.systemui.recents.events.ui.DismissTaskViewEvent;
import com.android.systemui.recents.events.ui.TaskViewDismissedEvent;
import com.android.systemui.recents.events.ui.UpdateFreeformTaskViewVisibilityEvent;
@@ -117,8 +119,6 @@
private static final int LAUNCH_NEXT_SCROLL_BASE_DURATION = 216;
private static final int LAUNCH_NEXT_SCROLL_INCR_DURATION = 32;
- private static final ArraySet<Task.TaskKey> EMPTY_TASK_SET = new ArraySet<>();
-
// The actions to perform when resetting to initial state,
@Retention(RetentionPolicy.SOURCE)
@IntDef({INITIAL_STATE_UPDATE_NONE, INITIAL_STATE_UPDATE_ALL, INITIAL_STATE_UPDATE_LAYOUT_ONLY})
@@ -598,17 +598,14 @@
if (tv == null) {
tv = mViewPool.pickUpViewFromPool(task, task);
if (task.isFreeformTask()) {
- tv.updateViewPropertiesToTaskTransform(transform, AnimationProps.IMMEDIATE,
- mRequestUpdateClippingListener);
+ updateTaskViewToTransform(tv, transform, AnimationProps.IMMEDIATE);
} else {
if (transform.rect.top <= mLayoutAlgorithm.mStackRect.top) {
- tv.updateViewPropertiesToTaskTransform(
- mLayoutAlgorithm.getBackOfStackTransform(),
- AnimationProps.IMMEDIATE, mRequestUpdateClippingListener);
+ updateTaskViewToTransform(tv, mLayoutAlgorithm.getBackOfStackTransform(),
+ AnimationProps.IMMEDIATE);
} else {
- tv.updateViewPropertiesToTaskTransform(
- mLayoutAlgorithm.getFrontOfStackTransform(),
- AnimationProps.IMMEDIATE, mRequestUpdateClippingListener);
+ updateTaskViewToTransform(tv, mLayoutAlgorithm.getFrontOfStackTransform(),
+ AnimationProps.IMMEDIATE);
}
}
} else {
@@ -1215,7 +1212,7 @@
TaskStackLayoutAlgorithm.StackState.getStackStateForStack(mStack));
mLayoutAlgorithm.initialize(mWindowRect, mStackBounds,
TaskStackLayoutAlgorithm.StackState.getStackStateForStack(mStack));
- updateLayoutAlgorithm(false /* boundScroll */, EMPTY_TASK_SET);
+ updateLayoutAlgorithm(false /* boundScroll */, mIgnoreTasks);
// If this is the first layout, then scroll to the front of the stack, then update the
// TaskViews with the stack so that we can lay them out
@@ -1225,7 +1222,7 @@
}
// Rebind all the views, including the ignore ones
- bindVisibleTaskViews(mStackScroller.getStackScroll(), EMPTY_TASK_SET,
+ bindVisibleTaskViews(mStackScroller.getStackScroll(), mIgnoreTasks,
false /* ignoreTaskOverrides */);
// Measure each of the TaskViews
@@ -1266,7 +1263,7 @@
mTmpTaskViews.addAll(mViewPool.getViews());
int taskViewCount = mTmpTaskViews.size();
for (int i = 0; i < taskViewCount; i++) {
- layoutTaskView(mTmpTaskViews.get(i));
+ layoutTaskView(changed, mTmpTaskViews.get(i));
}
if (changed) {
@@ -1274,8 +1271,9 @@
mStackScroller.boundScroll();
}
}
+
// Relayout all of the task views including the ignored ones
- relayoutTaskViews(AnimationProps.IMMEDIATE, EMPTY_TASK_SET);
+ relayoutTaskViews(AnimationProps.IMMEDIATE, mIgnoreTasks);
clipTaskViews();
if (mAwaitingFirstLayout || !mEnterAnimationComplete) {
@@ -1287,16 +1285,21 @@
/**
* Lays out a TaskView.
*/
- private void layoutTaskView(TaskView tv) {
- if (tv.getBackground() != null) {
- tv.getBackground().getPadding(mTmpRect);
+ private void layoutTaskView(boolean changed, TaskView tv) {
+ if (changed) {
+ if (tv.getBackground() != null) {
+ tv.getBackground().getPadding(mTmpRect);
+ } else {
+ mTmpRect.setEmpty();
+ }
+ Rect taskRect = mStableLayoutAlgorithm.mTaskRect;
+ tv.cancelTransformAnimation();
+ tv.layout(taskRect.left - mTmpRect.left, taskRect.top - mTmpRect.top,
+ taskRect.right + mTmpRect.right, taskRect.bottom + mTmpRect.bottom);
} else {
- mTmpRect.setEmpty();
+ // If the layout has not changed, then just lay it out again in-place
+ tv.layout(tv.getLeft(), tv.getTop(), tv.getRight(), tv.getBottom());
}
- Rect taskRect = mStableLayoutAlgorithm.mTaskRect;
- tv.cancelTransformAnimation();
- tv.layout(taskRect.left - mTmpRect.left, taskRect.top - mTmpRect.top,
- taskRect.right + mTmpRect.right, taskRect.bottom + mTmpRect.bottom);
}
/** Handler for the first layout. */
@@ -1320,7 +1323,8 @@
}
// Update the stack action button visibility
- if (mStackScroller.getStackScroll() < SHOW_STACK_ACTION_BUTTON_SCROLL_THRESHOLD) {
+ if (mStackScroller.getStackScroll() < SHOW_STACK_ACTION_BUTTON_SCROLL_THRESHOLD &&
+ mStack.getTaskCount() > 0) {
EventBus.getDefault().send(new ShowStackActionButtonEvent(false /* translate */));
} else {
EventBus.getDefault().send(new HideStackActionButtonEvent());
@@ -1445,6 +1449,26 @@
}
@Override
+ public void onStackTasksRemoved(TaskStack stack) {
+ // Reset the focused task
+ resetFocusedTask(getFocusedTask());
+
+ // Return all the views to the pool
+ List<TaskView> taskViews = new ArrayList<>();
+ taskViews.addAll(getTaskViews());
+ for (int i = taskViews.size() - 1; i >= 0; i--) {
+ mViewPool.returnViewToPool(taskViews.get(i));
+ }
+
+ // Remove all the ignore tasks
+ mIgnoreTasks.clear();
+
+ // If there are no remaining tasks, then just close recents
+ EventBus.getDefault().send(new AllTaskViewsDismissedEvent(
+ R.string.recents_empty_message_dismissed_all));
+ }
+
+ @Override
public void onStackTasksUpdated(TaskStack stack) {
// Update the layout and immediately layout
updateLayoutAlgorithm(false /* boundScroll */);
@@ -1509,7 +1533,7 @@
}
addViewInLayout(tv, insertIndex, params, true /* preventRequestLayout */);
measureTaskView(tv);
- layoutTaskView(tv);
+ layoutTaskView(true /* changed */, tv);
}
} else {
attachViewToParent(tv, insertIndex, tv.getLayoutParams());
@@ -1595,7 +1619,8 @@
if (mEnterAnimationComplete) {
if (prevScroll > SHOW_STACK_ACTION_BUTTON_SCROLL_THRESHOLD &&
- curScroll <= SHOW_STACK_ACTION_BUTTON_SCROLL_THRESHOLD) {
+ curScroll <= SHOW_STACK_ACTION_BUTTON_SCROLL_THRESHOLD &&
+ mStack.getTaskCount() > 0) {
EventBus.getDefault().send(new ShowStackActionButtonEvent(true /* translate */));
} else if (prevScroll < HIDE_STACK_ACTION_BUTTON_SCROLL_THRESHOLD &&
curScroll >= HIDE_STACK_ACTION_BUTTON_SCROLL_THRESHOLD) {
@@ -1703,14 +1728,42 @@
}
}
- public final void onBusEvent(final DismissTaskViewEvent event) {
+ public final void onBusEvent(DismissTaskViewEvent event) {
// For visible children, defer removing the task until after the animation
- mAnimationHelper.startDeleteTaskAnimation(event.task, event.taskView,
- event.getAnimationTrigger());
+ mAnimationHelper.startDeleteTaskAnimation(event.taskView, event.getAnimationTrigger());
+ }
+
+ public final void onBusEvent(final DismissAllTaskViewsEvent event) {
+ // Keep track of the tasks which will have their data removed
+ ArrayList<Task> tasks = new ArrayList<>(mStack.getStackTasks());
+ mAnimationHelper.startDeleteAllTasksAnimation(getTaskViews(), event.getAnimationTrigger());
+ event.addPostAnimationCallback(new Runnable() {
+ @Override
+ public void run() {
+ // Announce for accessibility
+ announceForAccessibility(getContext().getString(
+ R.string.accessibility_recents_all_items_dismissed));
+
+ // Remove all tasks and delete the task data for all tasks
+ mStack.removeAllTasks();
+ for (int i = tasks.size() - 1; i >= 0; i--) {
+ EventBus.getDefault().send(new DeleteTaskDataEvent(tasks.get(i)));
+ }
+
+ MetricsLogger.action(getContext(), MetricsEvent.OVERVIEW_DISMISS_ALL);
+ }
+ });
+
}
public final void onBusEvent(TaskViewDismissedEvent event) {
- removeTaskViewFromStack(event.taskView, event.task);
+ // Announce for accessibility
+ announceForAccessibility(getContext().getString(
+ R.string.accessibility_recents_item_dismissed, event.task.title));
+
+ // Remove the task from the stack
+ mStack.removeTask(event.task, new AnimationProps(DEFAULT_SYNC_STACK_DURATION,
+ Interpolators.FAST_OUT_SLOW_IN), false /* fromDockGesture */);
EventBus.getDefault().send(new DeleteTaskDataEvent(event.task));
MetricsLogger.action(getContext(), MetricsEvent.OVERVIEW_DISMISS,
@@ -1946,28 +1999,16 @@
}
}
- // Trigger a new layout and scroll to the initial state
- mInitialState = event.fromMultiWindow
- ? INITIAL_STATE_UPDATE_ALL
- : INITIAL_STATE_UPDATE_LAYOUT_ONLY;
+ // Trigger a new layout and update to the initial state if necessary
+ if (event.fromMultiWindow) {
+ mInitialState = INITIAL_STATE_UPDATE_ALL;
+ } else if (event.fromOrientationChange) {
+ mInitialState = INITIAL_STATE_UPDATE_LAYOUT_ONLY;
+ }
requestLayout();
}
/**
- * Removes the task from the stack, and updates the focus to the next task in the stack if the
- * removed TaskView was focused.
- */
- private void removeTaskViewFromStack(TaskView tv, Task task) {
- // Announce for accessibility
- tv.announceForAccessibility(getContext().getString(
- R.string.accessibility_recents_item_dismissed, task.title));
-
- // Remove the task from the stack
- mStack.removeTask(task, new AnimationProps(DEFAULT_SYNC_STACK_DURATION,
- Interpolators.FAST_OUT_SLOW_IN), false /* fromDockGesture */);
- }
-
- /**
* Starts an alpha animation on the freeform workspace background.
*/
private void animateFreeformWorkspaceBackgroundAlpha(int targetAlpha,
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java
index aed19c3..ee0de1a 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java
@@ -356,6 +356,11 @@
return;
}
+ // Disallow tapping above and below the stack to dismiss recents
+ if (x > mSv.mLayoutAlgorithm.mStackRect.left && x < mSv.mLayoutAlgorithm.mStackRect.right) {
+ return;
+ }
+
// If tapping on the freeform workspace background, just launch the first freeform task
SystemServicesProxy ssp = Recents.getSystemServices();
if (ssp.hasFreeformWorkspaceSupport()) {
@@ -507,13 +512,13 @@
tv.setClipViewInStack(true);
// Re-enable touch events from this task view
tv.setTouchEnabled(true);
+ // Remove the task view from the stack
+ EventBus.getDefault().send(new TaskViewDismissedEvent(tv.getTask(), tv));
// Update the scroll to the final scroll position from onBeginDrag()
mSv.getScroller().setStackScroll(mTargetStackScroll, null);
// Update the focus state to the final focus state
mSv.getStackAlgorithm().setFocusState(TaskStackLayoutAlgorithm.STATE_UNFOCUSED);
mSv.getStackAlgorithm().clearUnfocusedTaskOverrides();
- // Remove the task view from the stack
- EventBus.getDefault().send(new TaskViewDismissedEvent(tv.getTask(), tv));
// Stop tracking this deletion animation
mSwipeHelperAnimations.remove(v);
// Keep track of deletions by keyboard
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
index c085d80..f8ed700 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
@@ -384,7 +384,7 @@
void dismissTask() {
// Animate out the view and call the callback
final TaskView tv = this;
- DismissTaskViewEvent dismissEvent = new DismissTaskViewEvent(tv, mTask);
+ DismissTaskViewEvent dismissEvent = new DismissTaskViewEvent(tv);
dismissEvent.addPostAnimationCallback(new Runnable() {
@Override
public void run() {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java
index ddea4d9..570ff8a 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java
@@ -267,9 +267,9 @@
lp = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT, Gravity.START | Gravity.CENTER_VERTICAL);
lp.setMarginStart(mHeaderBarHeight);
- lp.rightMargin = mMoveTaskButton != null
+ lp.setMarginEnd(mMoveTaskButton != null
? 2 * mHeaderBarHeight
- : mHeaderBarHeight;
+ : mHeaderBarHeight);
title.setLayoutParams(lp);
if (secondaryButton != null) {
lp = new FrameLayout.LayoutParams(mHeaderBarHeight, mHeaderBarHeight, Gravity.END);
@@ -459,7 +459,7 @@
if (!mTitleView.getText().toString().equals(t.title)) {
mTitleView.setText(t.title);
}
- mTitleView.setContentDescription(t.contentDescription);
+ mTitleView.setContentDescription(t.titleDescription);
mTitleView.setTextColor(t.useLightOnPrimaryColor ?
mTaskBarViewLightTextColor : mTaskBarViewDarkTextColor);
if (!t.isDockable && ssp.hasDockedTask()) {
@@ -501,6 +501,7 @@
// In accessibility, a single click on the focused app info button will show it
if (touchExplorationEnabled) {
+ mIconView.setContentDescription(t.appInfoDescription);
mIconView.setOnClickListener(this);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java
index 3eeabc7..e5ac0d3 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java
@@ -141,9 +141,9 @@
return;
}
+ int viewWidth = mTaskViewRect.width();
+ int viewHeight = mTaskViewRect.height();
if (mBitmapShader != null) {
- int viewWidth = mTaskViewRect.width();
- int viewHeight = mTaskViewRect.height();
// We are drawing the thumbnail in the same orientation, so just fit the width
int thumbnailWidth = (int) (mThumbnailRect.width() * mThumbnailScale);
@@ -180,6 +180,9 @@
canvas.restoreToCount(count);
}
+ } else {
+ canvas.drawRoundRect(0, 0, viewWidth, viewHeight, mCornerRadius, mCornerRadius,
+ mBgFillPaint);
}
}
@@ -319,12 +322,12 @@
mDisabledInSafeMode = disabledInSafeMode;
if (t.thumbnail != null) {
setThumbnail(t.thumbnail, thumbnailInfo);
- if (t.colorBackground != 0) {
- mBgFillPaint.setColor(t.colorBackground);
- }
} else {
setThumbnail(null, null);
}
+ if (t.colorBackground != 0) {
+ mBgFillPaint.setColor(t.colorBackground);
+ }
}
/** Unbinds the thumbnail view from the task */
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewTransform.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewTransform.java
index dc76e61..b512393 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewTransform.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewTransform.java
@@ -226,4 +226,9 @@
v.getViewBounds().setClipBottom(0);
v.setLeftTopRightBottom(0, 0, 0, 0);
}
+
+ @Override
+ public String toString() {
+ return "R: " + rect + " V: " + visible;
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java b/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java
index e8cf126..ddd3ea1 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java
@@ -97,6 +97,9 @@
if (mVisible != visible) {
mVisible = visible;
mView.setVisibility(visible ? View.VISIBLE : View.INVISIBLE);
+
+ // Update state because animations won't finish.
+ mView.setMinimizedDockStack(mMinimized);
}
}
});
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
index 7a933cd..601d910 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
@@ -134,6 +134,7 @@
private ValueAnimator mCurrentAnimator;
private boolean mEntranceAnimationRunning;
private GestureDetector mGestureDetector;
+ private boolean mDockedStackMinimized;
private final AccessibilityDelegate mHandleDelegate = new AccessibilityDelegate() {
@Override
@@ -538,6 +539,7 @@
: mBackground.getWidth());
mBackground.setScaleX(MINIMIZE_DOCK_SCALE);
}
+ mDockedStackMinimized = minimized;
}
public void setMinimizedDockStack(boolean minimized, long animDuration) {
@@ -566,6 +568,7 @@
.setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
.setDuration(animDuration)
.start();
+ mDockedStackMinimized = minimized;
}
private void resetBackground() {
@@ -883,7 +886,7 @@
public final void onBusEvent(UndockingTaskEvent undockingTaskEvent) {
int dockSide = mWindowManagerProxy.getDockSide();
- if (dockSide != WindowManager.DOCKED_INVALID) {
+ if (dockSide != WindowManager.DOCKED_INVALID && !mDockedStackMinimized) {
startDragging(false /* animate */, false /* touching */);
SnapTarget target = dockSideTopLeft(dockSide)
? mSnapAlgorithm.getDismissEndTarget()
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index 1c5d28a..4ed6426 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -19,7 +19,9 @@
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.app.ActivityManager;
+import android.app.ActivityManager.StackId;
import android.app.ActivityManagerNative;
+import android.app.ActivityOptions;
import android.app.KeyguardManager;
import android.app.Notification;
import android.app.NotificationManager;
@@ -127,6 +129,8 @@
SystemProperties.getBoolean("debug.enable_remote_input", true);
public static final boolean ENABLE_CHILD_NOTIFICATIONS
= SystemProperties.getBoolean("debug.child_notifs", true);
+ public static final boolean FORCE_REMOTE_INPUT_HISTORY =
+ SystemProperties.getBoolean("debug.force_remoteinput_history", false);
protected static final int MSG_SHOW_RECENT_APPS = 1019;
protected static final int MSG_HIDE_RECENT_APPS = 1020;
@@ -182,6 +186,13 @@
protected boolean mVisible;
protected ArraySet<Entry> mHeadsUpEntriesToRemoveOnSwitch = new ArraySet<>();
+ /**
+ * Notifications with keys in this set are not actually around anymore. We kept them around
+ * when they were canceled in response to a remote input interaction. This allows us to show
+ * what you replied and allows you to continue typing into it.
+ */
+ protected ArraySet<String> mKeysKeptForRemoteInput = new ArraySet<>();
+
// mScreenOnFromKeyguard && mVisible.
private boolean mVisibleToUser;
@@ -338,7 +349,7 @@
}, afterKeyguardGone);
return true;
} else {
- return super.onClickHandler(view, pendingIntent, fillInIntent);
+ return superOnClickHandler(view, pendingIntent, fillInIntent);
}
}
@@ -375,7 +386,8 @@
private boolean superOnClickHandler(View view, PendingIntent pendingIntent,
Intent fillInIntent) {
- return super.onClickHandler(view, pendingIntent, fillInIntent);
+ return super.onClickHandler(view, pendingIntent, fillInIntent,
+ StackId.FULLSCREEN_WORKSPACE_STACK_ID);
}
private boolean handleRemoteInput(View view, PendingIntent pendingIntent, Intent fillInIntent) {
@@ -566,6 +578,7 @@
public void run() {
processForRemoteInput(sbn.getNotification());
String key = sbn.getKey();
+ mKeysKeptForRemoteInput.remove(key);
boolean isUpdate = mNotificationData.get(key) != null;
// In case we don't allow child notifications, we ignore children of
// notifications that have a summary, since we're not going to show them
@@ -904,7 +917,7 @@
}
}
- protected View bindVetoButtonClickListener(View row, StatusBarNotification n) {
+ protected View bindVetoButtonClickListener(View row, final StatusBarNotification n) {
View vetoButton = row.findViewById(R.id.veto);
final String _pkg = n.getPackageName();
final String _tag = n.getTag();
@@ -917,6 +930,11 @@
mContext.getString(R.string.accessibility_notification_dismissed));
try {
mBarService.onNotificationClear(_pkg, _tag, _id, _userId);
+ if (FORCE_REMOTE_INPUT_HISTORY
+ && mKeysKeptForRemoteInput.contains(n.getKey())) {
+ removeNotification(n.getKey(), null);
+ mKeysKeptForRemoteInput.remove(n.getKey());
+ }
} catch (RemoteException ex) {
// system process is dead if we're here.
@@ -975,7 +993,7 @@
}
TaskStackBuilder.create(mContext)
.addNextIntentWithParentStack(intent)
- .startActivities(null,
+ .startActivities(getActivityOptions(),
new UserHandle(UserHandle.getUserId(appUid)));
overrideActivityPendingAppTransition(keyguardShowing);
} catch (RemoteException e) {
@@ -1725,7 +1743,7 @@
} catch (RemoteException e) {
}
try {
- intent.send();
+ intent.send(null, 0, null, null, null, null, getActivityOptions());
} catch (PendingIntent.CanceledException e) {
// the stack trace isn't very helpful here.
// Just log the exception message.
@@ -1833,7 +1851,8 @@
}
}
try {
- intent.send();
+ intent.send(null, 0, null, null, null, null,
+ getActivityOptions());
} catch (PendingIntent.CanceledException e) {
// the stack trace isn't very helpful here.
// Just log the exception message.
@@ -1909,6 +1928,14 @@
}
}
+ protected Bundle getActivityOptions() {
+ // Anything launched from the notification shade should always go into the
+ // fullscreen stack.
+ ActivityOptions options = ActivityOptions.makeBasic();
+ options.setLaunchStackId(StackId.FULLSCREEN_WORKSPACE_STACK_ID);
+ return options.toBundle();
+ }
+
protected void visibilityChanged(boolean visible) {
if (mVisible != visible) {
mVisible = visible;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcutKeysLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcutKeysLayout.java
index ba3e774..6746a67 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcutKeysLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcutKeysLayout.java
@@ -29,13 +29,16 @@
*/
public final class KeyboardShortcutKeysLayout extends ViewGroup {
private int mLineHeight;
+ private final Context mContext;
public KeyboardShortcutKeysLayout(Context context) {
super(context);
+ this.mContext = context;
}
public KeyboardShortcutKeysLayout(Context context, AttributeSet attrs) {
super(context, attrs);
+ this.mContext = context;
}
@Override
@@ -104,7 +107,9 @@
protected void onLayout(boolean changed, int l, int t, int r, int b) {
int childCount = getChildCount();
int fullRowWidth = r - l;
- int xPos = getPaddingLeft();
+ int xPos = isRTL()
+ ? fullRowWidth - getPaddingRight()
+ : getPaddingLeft();
int yPos = getPaddingTop();
int lastHorizontalSpacing = 0;
// The index of the child which starts the current row.
@@ -117,18 +122,25 @@
int currentChildWidth = currentChild.getMeasuredWidth();
LayoutParams lp = (LayoutParams) currentChild.getLayoutParams();
- // If the current child does not fit on this row.
- if (xPos + currentChildWidth > fullRowWidth) {
+ boolean childDoesNotFitOnRow = isRTL()
+ ? xPos - getPaddingLeft() - currentChildWidth < 0
+ : xPos + currentChildWidth > fullRowWidth;
+
+ if (childDoesNotFitOnRow) {
// Layout all the children on this row but the current one.
layoutChildrenOnRow(rowStartIdx, i, fullRowWidth, xPos, yPos,
lastHorizontalSpacing);
// Update the positions for starting on the new row.
- xPos = getPaddingLeft();
+ xPos = isRTL()
+ ? fullRowWidth - getPaddingRight()
+ : getPaddingLeft();
yPos += mLineHeight;
rowStartIdx = i;
}
- xPos += currentChildWidth + lp.mHorizontalSpacing;
+ xPos = isRTL()
+ ? xPos - currentChildWidth - lp.mHorizontalSpacing
+ : xPos + currentChildWidth + lp.mHorizontalSpacing;
lastHorizontalSpacing = lp.mHorizontalSpacing;
}
}
@@ -148,21 +160,41 @@
private void layoutChildrenOnRow(int startIndex, int endIndex, int fullRowWidth, int xPos,
int yPos, int lastHorizontalSpacing) {
- int freeSpace = fullRowWidth - xPos + lastHorizontalSpacing;
- xPos = getPaddingLeft() + freeSpace;
+ if (!isRTL()) {
+ xPos = getPaddingLeft() + fullRowWidth - xPos + lastHorizontalSpacing;
+ }
for (int j = startIndex; j < endIndex; ++j) {
View currentChild = getChildAt(j);
+ int currentChildWidth = currentChild.getMeasuredWidth();
+ LayoutParams lp = (LayoutParams) currentChild.getLayoutParams();
+ if (isRTL() && j == startIndex) {
+ xPos = fullRowWidth - xPos - getPaddingRight() - currentChildWidth
+ - lp.mHorizontalSpacing;
+ }
+
currentChild.layout(
xPos,
yPos,
- xPos + currentChild.getMeasuredWidth(),
+ xPos + currentChildWidth,
yPos + currentChild.getMeasuredHeight());
- xPos += currentChild.getMeasuredWidth()
- + ((LayoutParams) currentChild.getLayoutParams()).mHorizontalSpacing;
+
+ if (isRTL()) {
+ int nextChildWidth = j < endIndex - 1
+ ? getChildAt(j + 1).getMeasuredWidth()
+ : 0;
+ xPos -= nextChildWidth + lp.mHorizontalSpacing;
+ } else {
+ xPos += currentChildWidth + lp.mHorizontalSpacing;
+ }
}
}
+ private boolean isRTL() {
+ return mContext.getResources().getConfiguration().getLayoutDirection()
+ == View.LAYOUT_DIRECTION_RTL;
+ }
+
public static class LayoutParams extends ViewGroup.LayoutParams {
public final int mHorizontalSpacing;
public final int mVerticalSpacing;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java
index 8fe60a0..2b365dc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java
@@ -245,7 +245,57 @@
systemGroup.addItem(new KeyboardShortcutInfo(
mContext.getString(R.string.keyboard_shortcut_group_system_recents),
KeyEvent.KEYCODE_TAB, KeyEvent.META_ALT_ON));
+ systemGroup.addItem(new KeyboardShortcutInfo(
+ mContext.getString(
+ R.string.keyboard_shortcut_group_system_notifications),
+ KeyEvent.KEYCODE_N, KeyEvent.META_META_ON));
+ systemGroup.addItem(new KeyboardShortcutInfo(
+ mContext.getString(
+ R.string.keyboard_shortcut_group_system_shortcuts_helper),
+ KeyEvent.KEYCODE_SLASH, KeyEvent.META_META_ON));
+ systemGroup.addItem(new KeyboardShortcutInfo(
+ mContext.getString(
+ R.string.keyboard_shortcut_group_system_switch_input),
+ KeyEvent.KEYCODE_SPACE, KeyEvent.META_META_ON));
result.add(systemGroup);
+
+ KeyboardShortcutGroup applicationGroup = new KeyboardShortcutGroup(
+ mContext.getString(R.string.keyboard_shortcut_group_applications),
+ true);
+ applicationGroup.addItem(new KeyboardShortcutInfo(
+ mContext.getString(
+ R.string.keyboard_shortcut_group_applications_assist),
+ KeyEvent.KEYCODE_UNKNOWN, KeyEvent.META_META_ON));
+ applicationGroup.addItem(new KeyboardShortcutInfo(
+ mContext.getString(
+ R.string.keyboard_shortcut_group_applications_browser),
+ KeyEvent.KEYCODE_B, KeyEvent.META_META_ON));
+ applicationGroup.addItem(new KeyboardShortcutInfo(
+ mContext.getString(
+ R.string.keyboard_shortcut_group_applications_contacts),
+ KeyEvent.KEYCODE_C, KeyEvent.META_META_ON));
+ applicationGroup.addItem(new KeyboardShortcutInfo(
+ mContext.getString(
+ R.string.keyboard_shortcut_group_applications_email),
+ KeyEvent.KEYCODE_E, KeyEvent.META_META_ON));
+ applicationGroup.addItem(new KeyboardShortcutInfo(
+ mContext.getString(
+ R.string.keyboard_shortcut_group_applications_im),
+ KeyEvent.KEYCODE_T, KeyEvent.META_META_ON));
+ applicationGroup.addItem(new KeyboardShortcutInfo(
+ mContext.getString(
+ R.string.keyboard_shortcut_group_applications_music),
+ KeyEvent.KEYCODE_P, KeyEvent.META_META_ON));
+ applicationGroup.addItem(new KeyboardShortcutInfo(
+ mContext.getString(
+ R.string.keyboard_shortcut_group_applications_youtube),
+ KeyEvent.KEYCODE_Y, KeyEvent.META_META_ON));
+ applicationGroup.addItem(new KeyboardShortcutInfo(
+ mContext.getString(
+ R.string.keyboard_shortcut_group_applications_calendar),
+ KeyEvent.KEYCODE_L, KeyEvent.META_META_ON));
+ result.add(applicationGroup);
+
showKeyboardShortcutsDialog(result);
}
}, deviceId);
@@ -354,11 +404,15 @@
return null;
}
String displayLabelString;
- if (info.getKeycode() == KeyEvent.KEYCODE_UNKNOWN) {
+ if (info.getBaseCharacter() > Character.MIN_VALUE) {
displayLabelString = String.valueOf(info.getBaseCharacter());
} else if (SPECIAL_CHARACTER_NAMES.get(info.getKeycode()) != null) {
displayLabelString = SPECIAL_CHARACTER_NAMES.get(info.getKeycode());
} else {
+ // Special case for shortcuts with no base key or keycode.
+ if (info.getKeycode() == KeyEvent.KEYCODE_UNKNOWN) {
+ return shortcutKeys;
+ }
// TODO: Have a generic map for when we don't have the device's.
char displayLabel = mKeyCharacterMap == null
? 0 : mKeyCharacterMap.getDisplayLabel(info.getKeycode());
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationSettingsIconRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationSettingsIconRow.java
index a3e78c1..88aafe0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationSettingsIconRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationSettingsIconRow.java
@@ -92,7 +92,7 @@
mAnimating = false;
mSnapping = false;
mDismissing = false;
- setIconLocation(true /* on left */);
+ setIconLocation(true /* on left */, true /* force */);
if (mListener != null) {
mListener.onSettingsIconRowReset(this);
}
@@ -104,6 +104,7 @@
public void setNotificationRowParent(ExpandableNotificationRow parent) {
mParent = parent;
+ setIconLocation(mOnLeft, true /* force */);
}
public void setAppName(String appName) {
@@ -183,7 +184,7 @@
if (isIconLocationChange(transX)) {
setGearAlpha(0f);
}
- setIconLocation(transX > 0 /* fromLeft */);
+ setIconLocation(transX > 0 /* fromLeft */, false /* force */);
mFadeAnimator = ValueAnimator.ofFloat(mGearIcon.getAlpha(), 1);
mFadeAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
@@ -220,12 +221,20 @@
mFadeAnimator.start();
}
- public void setIconLocation(boolean onLeft) {
- if (onLeft == mOnLeft || mSnapping) {
- // Same side? Do nothing.
+ @Override
+ public void onRtlPropertiesChanged(int layoutDirection) {
+ setIconLocation(mOnLeft, true /* force */);
+ }
+
+ public void setIconLocation(boolean onLeft, boolean force) {
+ if ((!force && onLeft == mOnLeft) || mSnapping || mParent == null) {
+ // Do nothing
return;
}
- setTranslationX(onLeft ? 0 : (mParent.getWidth() - mHorizSpaceForGear));
+ final boolean isRtl = mParent.isLayoutRtl();
+ final float left = isRtl ? -(mParent.getWidth() - mHorizSpaceForGear) : 0;
+ final float right = isRtl ? 0 : (mParent.getWidth() - mHorizSpaceForGear);
+ setTranslationX(onLeft ? left : right);
mOnLeft = onLeft;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/RemoteInputController.java b/packages/SystemUI/src/com/android/systemui/statusbar/RemoteInputController.java
index d7e47c2..5fea674 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/RemoteInputController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/RemoteInputController.java
@@ -21,6 +21,8 @@
import com.android.systemui.statusbar.policy.HeadsUpManager;
import com.android.systemui.statusbar.policy.RemoteInputView;
+import android.util.ArraySet;
+
import java.lang.ref.WeakReference;
import java.util.ArrayList;
@@ -29,7 +31,8 @@
*/
public class RemoteInputController {
- private final ArrayList<WeakReference<NotificationData.Entry>> mRemoteInputs = new ArrayList<>();
+ private final ArrayList<WeakReference<NotificationData.Entry>> mOpen = new ArrayList<>();
+ private final ArraySet<String> mSpinning = new ArraySet<>();
private final ArrayList<Callback> mCallbacks = new ArrayList<>(3);
private final HeadsUpManager mHeadsUpManager;
@@ -44,7 +47,7 @@
boolean found = pruneWeakThenRemoveAndContains(
entry /* contains */, null /* remove */);
if (!found) {
- mRemoteInputs.add(new WeakReference<>(entry));
+ mOpen.add(new WeakReference<>(entry));
}
apply(entry);
@@ -58,6 +61,18 @@
apply(entry);
}
+ public void addSpinning(String key) {
+ mSpinning.add(key);
+ }
+
+ public void removeSpinning(String key) {
+ mSpinning.remove(key);
+ }
+
+ public boolean isSpinning(String key) {
+ return mSpinning.contains(key);
+ }
+
private void apply(NotificationData.Entry entry) {
mHeadsUpManager.setRemoteInputActive(entry, isRemoteInputActive(entry));
boolean remoteInputActive = isRemoteInputActive();
@@ -79,7 +94,7 @@
*/
public boolean isRemoteInputActive() {
pruneWeakThenRemoveAndContains(null /* contains */, null /* remove */);
- return !mRemoteInputs.isEmpty();
+ return !mOpen.isEmpty();
}
/**
@@ -91,10 +106,10 @@
private boolean pruneWeakThenRemoveAndContains(
NotificationData.Entry contains, NotificationData.Entry remove) {
boolean found = false;
- for (int i = mRemoteInputs.size() - 1; i >= 0; i--) {
- NotificationData.Entry item = mRemoteInputs.get(i).get();
+ for (int i = mOpen.size() - 1; i >= 0; i--) {
+ NotificationData.Entry item = mOpen.get(i).get();
if (item == null || item == remove) {
- mRemoteInputs.remove(i);
+ mOpen.remove(i);
} else if (item == contains) {
found = true;
}
@@ -108,7 +123,16 @@
mCallbacks.add(callback);
}
+ public void remoteInputSent(NotificationData.Entry entry) {
+ int N = mCallbacks.size();
+ for (int i = 0; i < N; i++) {
+ mCallbacks.get(i).onRemoteInputSent(entry);
+ }
+ }
+
public interface Callback {
- void onRemoteInputActive(boolean active);
+ default void onRemoteInputActive(boolean active) {}
+
+ default void onRemoteInputSent(NotificationData.Entry entry) {}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationBarController.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationBarController.java
index bb43899..d9bf539 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationBarController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationBarController.java
@@ -106,7 +106,7 @@
String category = getPackageCategory(packageName);
if (mFacetCategoryMap.containsKey(category)) {
- int index = mFacetCategoryMap.get(packageName);
+ int index = mFacetCategoryMap.get(category);
mFacetHasMultipleAppsCache.put(index, facetHasMultiplePackages(index));
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ExpandableIndicator.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ExpandableIndicator.java
index 04095e7..3fdc35c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ExpandableIndicator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ExpandableIndicator.java
@@ -23,6 +23,7 @@
public class ExpandableIndicator extends ImageView {
private boolean mExpanded;
+ private boolean mIsDefaultDirection = true;
public ExpandableIndicator(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -31,16 +32,14 @@
@Override
protected void onFinishInflate() {
super.onFinishInflate();
- final int res = mExpanded ? R.drawable.ic_volume_collapse_animation
- : R.drawable.ic_volume_expand_animation;
+ final int res = getDrawableResourceId(mExpanded);
setImageResource(res);
}
public void setExpanded(boolean expanded) {
if (expanded == mExpanded) return;
mExpanded = expanded;
- final int res = mExpanded ? R.drawable.ic_volume_expand_animation
- : R.drawable.ic_volume_collapse_animation;
+ final int res = getDrawableResourceId(!mExpanded);
// workaround to reset drawable
final AnimatedVectorDrawable avd = (AnimatedVectorDrawable) getContext()
.getDrawable(res).getConstantState().newDrawable();
@@ -48,4 +47,19 @@
avd.forceAnimationOnUI();
avd.start();
}
+
+ /** Whether the icons are using the default direction or the opposite */
+ public void setDefaultDirection(boolean isDefaultDirection) {
+ mIsDefaultDirection = isDefaultDirection;
+ }
+
+ private int getDrawableResourceId(boolean expanded) {
+ if (mIsDefaultDirection) {
+ return expanded ? R.drawable.ic_volume_collapse_animation
+ : R.drawable.ic_volume_expand_animation;
+ } else {
+ return expanded ? R.drawable.ic_volume_expand_animation
+ : R.drawable.ic_volume_collapse_animation;
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenWallpaper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenWallpaper.java
index 65e7973..3812429 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenWallpaper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenWallpaper.java
@@ -85,7 +85,7 @@
// wallpaper.
final int lockWallpaperUserId =
mSelectedUser != null ? mSelectedUser.getIdentifier() : mCurrentUserId;
- ParcelFileDescriptor fd = mService.getWallpaper(null, WallpaperManager.FLAG_SET_LOCK,
+ ParcelFileDescriptor fd = mService.getWallpaper(null, WallpaperManager.FLAG_LOCK,
new Bundle(), lockWallpaperUserId);
if (fd != null) {
try {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ManagedProfileController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ManagedProfileController.java
index 63ee0c0..41eed56 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ManagedProfileController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ManagedProfileController.java
@@ -113,7 +113,8 @@
filter.addAction(Intent.ACTION_USER_SWITCHED);
filter.addAction(Intent.ACTION_MANAGED_PROFILE_ADDED);
filter.addAction(Intent.ACTION_MANAGED_PROFILE_REMOVED);
- filter.addAction(Intent.ACTION_MANAGED_PROFILE_AVAILABILITY_CHANGED);
+ filter.addAction(Intent.ACTION_MANAGED_PROFILE_AVAILABLE);
+ filter.addAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE);
mContext.registerReceiverAsUser(mReceiver, UserHandle.ALL, filter, null, null);
} else {
mContext.unregisterReceiver(mReceiver);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index 7486519..45e94f7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -225,7 +225,8 @@
public void onInflated(View v) {
mQsContainer = (QSContainer) v.findViewById(R.id.quick_settings_container);
mQsContainer.setPanelView(NotificationPanelView.this);
- mQsContainer.getHeader().setOnClickListener(NotificationPanelView.this);
+ mQsContainer.getHeader().findViewById(R.id.expand_indicator)
+ .setOnClickListener(NotificationPanelView.this);
}
});
mClockView = (TextView) findViewById(R.id.clock_view);
@@ -789,8 +790,9 @@
}
private boolean isInQsArea(float x, float y) {
- return (x >= mQsContainer.getX() && x <= mQsContainer.getX() + mQsContainer.getWidth()) &&
- (y <= mNotificationStackScroller.getBottomMostNotificationBottom()
+ return (x >= mQsDensityContainer.getX()
+ && x <= mQsDensityContainer.getX() + mQsDensityContainer.getWidth())
+ && (y <= mNotificationStackScroller.getBottomMostNotificationBottom()
|| y <= mQsContainer.getY() + mQsContainer.getHeight());
}
@@ -1208,7 +1210,9 @@
}
private String getKeyguardOrLockScreenString() {
- if (mStatusBarState == StatusBarState.KEYGUARD) {
+ if (mQsContainer.isCustomizing()) {
+ return getContext().getString(R.string.accessibility_desc_quick_settings_edit);
+ } else if (mStatusBarState == StatusBarState.KEYGUARD) {
return getContext().getString(R.string.accessibility_desc_lock_screen);
} else {
return getContext().getString(R.string.accessibility_desc_notification_shade);
@@ -1335,7 +1339,8 @@
return false;
}
View header = mKeyguardShowing ? mKeyguardStatusBar : mQsContainer.getHeader();
- boolean onHeader = x >= header.getX() && x <= header.getX() + header.getWidth()
+ boolean onHeader = x >= mQsDensityContainer.getX()
+ && x <= mQsDensityContainer.getX() + mQsDensityContainer.getWidth()
&& y >= header.getTop() && y <= header.getBottom();
if (mQsExpanded) {
return onHeader || (yDiff < 0 && isInQsArea(x, y));
@@ -1756,7 +1761,7 @@
@Override
public void onClick(View v) {
- if (v == mQsContainer.getHeader()) {
+ if (v.getId() == R.id.expand_indicator) {
onQsExpansionStarted();
if (mQsExpanded) {
flingSettings(0 /* vel */, false /* expand */, null, true /* isClick */);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQuickSettingsContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQuickSettingsContainer.java
index 960515b..35fb2a5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQuickSettingsContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQuickSettingsContainer.java
@@ -35,6 +35,7 @@
public class NotificationsQuickSettingsContainer extends FrameLayout
implements ViewStub.OnInflateListener, DensityContainer.InflateListener {
+
private DensityContainer mQsContainer;
private View mUserSwitcher;
private View mStackScroller;
@@ -43,6 +44,9 @@
private boolean mQsExpanded;
private boolean mCustomizerAnimating;
+ private int mBottomPadding;
+ private int mStackScrollerMargin;
+
public NotificationsQuickSettingsContainer(Context context, AttributeSet attrs) {
super(context, attrs);
}
@@ -53,6 +57,7 @@
mQsContainer = (DensityContainer) findViewById(R.id.qs_density_container);
mQsContainer.addInflateListener(this);
mStackScroller = findViewById(R.id.notification_stack_scroller);
+ mStackScrollerMargin = ((LayoutParams) mStackScroller.getLayoutParams()).bottomMargin;
mKeyguardStatusBar = findViewById(R.id.keyguard_header);
ViewStub userSwitcher = (ViewStub) findViewById(R.id.keyguard_user_switcher);
userSwitcher.setOnInflateListener(this);
@@ -75,7 +80,8 @@
@Override
public WindowInsets onApplyWindowInsets(WindowInsets insets) {
- setPadding(0, 0, 0, insets.getStableInsetBottom());
+ mBottomPadding = insets.getStableInsetBottom();
+ setPadding(0, 0, 0, mBottomPadding);
return insets;
}
@@ -141,4 +147,22 @@
invalidate();
}
}
+
+ public void setCustomizerShowing(boolean isShowing) {
+ if (isShowing) {
+ // Clear out bottom paddings/margins so the qs customization can be full height.
+ setPadding(0, 0, 0, 0);
+ setBottomMargin(mStackScroller, 0);
+ } else {
+ setPadding(0, 0, 0, mBottomPadding);
+ setBottomMargin(mStackScroller, mStackScrollerMargin);
+ }
+
+ }
+
+ private void setBottomMargin(View v, int bottomMargin) {
+ LayoutParams params = (LayoutParams) v.getLayoutParams();
+ params.bottomMargin = bottomMargin;
+ v.setLayoutParams(params);
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index bb77c5b..c563eb6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -21,7 +21,9 @@
import android.animation.AnimatorListenerAdapter;
import android.annotation.NonNull;
import android.app.ActivityManager;
+import android.app.ActivityManager.StackId;
import android.app.ActivityManagerNative;
+import android.app.ActivityOptions;
import android.app.IActivityManager;
import android.app.Notification;
import android.app.PendingIntent;
@@ -876,7 +878,7 @@
DensityContainer container = (DensityContainer) mStatusBarWindow.findViewById(
R.id.qs_density_container);
if (container != null) {
- final QSTileHost qsh = new QSTileHost(mContext, this,
+ final QSTileHost qsh = SystemUIFactory.getInstance().createQSTileHost(mContext, this,
mBluetoothController, mLocationController, mRotationLockController,
mNetworkController, mZenModeController, mHotspotController,
mCastController, mFlashlightController,
@@ -1110,6 +1112,18 @@
mStatusBarKeyguardViewManager);
mFingerprintUnlockController.setStatusBarKeyguardViewManager(mStatusBarKeyguardViewManager);
mRemoteInputController.addCallback(mStatusBarKeyguardViewManager);
+
+ if (FORCE_REMOTE_INPUT_HISTORY) {
+ mRemoteInputController.addCallback(new RemoteInputController.Callback() {
+ @Override
+ public void onRemoteInputSent(Entry entry) {
+ if (mKeysKeptForRemoteInput.contains(entry.key)) {
+ removeNotification(entry.key, null);
+ }
+ }
+ });
+ }
+
mKeyguardViewMediatorCallback = keyguardViewMediator.getViewMediatorCallback();
mLightStatusBarController.setFingerprintUnlockController(mFingerprintUnlockController);
}
@@ -1378,6 +1392,42 @@
clearCurrentMediaNotification();
updateMediaMetaData(true, true);
}
+ if (FORCE_REMOTE_INPUT_HISTORY && mRemoteInputController.isSpinning(key)) {
+ Entry entry = mNotificationData.get(key);
+ StatusBarNotification sbn = entry.notification;
+
+ Notification.Builder b = Notification.Builder
+ .recoverBuilder(mContext, sbn.getNotification().clone());
+ CharSequence[] oldHistory = sbn.getNotification().extras
+ .getCharSequenceArray(Notification.EXTRA_REMOTE_INPUT_HISTORY);
+ CharSequence[] newHistory;
+ if (oldHistory == null) {
+ newHistory = new CharSequence[1];
+ } else {
+ newHistory = new CharSequence[oldHistory.length + 1];
+ for (int i = 0; i < oldHistory.length; i++) {
+ newHistory[i + 1] = oldHistory[i];
+ }
+ }
+ newHistory[0] = String.valueOf(entry.remoteInputText);
+ b.setRemoteInputHistory(newHistory);
+
+ Notification newNotification = b.build();
+
+ // Undo any compatibility view inflation
+ newNotification.contentView = sbn.getNotification().contentView;
+ newNotification.bigContentView = sbn.getNotification().bigContentView;
+ newNotification.headsUpContentView = sbn.getNotification().headsUpContentView;
+
+ StatusBarNotification newSbn = new StatusBarNotification(sbn.getPackageName(),
+ sbn.getOpPkg(),
+ sbn.getId(), sbn.getTag(), sbn.getUid(), sbn.getInitialPid(),
+ 0, newNotification, sbn.getUser(), sbn.getPostTime());
+
+ updateNotification(newSbn, null);
+ mKeysKeptForRemoteInput.add(entry.key);
+ return;
+ }
if (deferRemoval) {
mLatestRankingMap = ranking;
mHeadsUpEntriesToRemoveOnSwitch.add(mHeadsUpManager.getEntry(key));
@@ -3043,8 +3093,8 @@
null, mContext.getBasePackageName(),
intent,
intent.resolveTypeIfNeeded(mContext.getContentResolver()),
- null, null, 0, Intent.FLAG_ACTIVITY_NEW_TASK, null, null,
- UserHandle.CURRENT.getIdentifier());
+ null, null, 0, Intent.FLAG_ACTIVITY_NEW_TASK, null,
+ getActivityOptions(), UserHandle.CURRENT.getIdentifier());
} catch (RemoteException e) {
Log.w(TAG, "Unable to start activity", e);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
index c883cc9..0ac2e7c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
@@ -137,7 +137,8 @@
filter.addAction(AudioManager.ACTION_HEADSET_PLUG);
filter.addAction(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
filter.addAction(TelecomManager.ACTION_CURRENT_TTY_MODE_CHANGED);
- filter.addAction(Intent.ACTION_MANAGED_PROFILE_AVAILABILITY_CHANGED);
+ filter.addAction(Intent.ACTION_MANAGED_PROFILE_AVAILABLE);
+ filter.addAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE);
mContext.registerReceiver(mIntentReceiver, filter, null, mHandler);
// listen for user / profile change.
@@ -507,7 +508,8 @@
updateSimState(intent);
} else if (action.equals(TelecomManager.ACTION_CURRENT_TTY_MODE_CHANGED)) {
updateTTY(intent);
- } else if (action.equals(Intent.ACTION_MANAGED_PROFILE_AVAILABILITY_CHANGED)) {
+ } else if (action.equals(Intent.ACTION_MANAGED_PROFILE_AVAILABLE) ||
+ action.equals(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE)) {
updateQuietState();
updateManagedProfile();
} else if (action.equals(AudioManager.ACTION_HEADSET_PLUG)) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java
index 5dcd393..82496ac 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java
@@ -81,7 +81,7 @@
import java.util.Map;
/** Platform implementation of the quick settings tile host **/
-public final class QSTileHost implements QSTile.Host, Tunable {
+public class QSTileHost implements QSTile.Host, Tunable {
private static final String TAG = "QSTileHost";
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
@@ -450,7 +450,7 @@
}
}
- public static List<String> loadTileSpecs(Context context, String tileList) {
+ protected List<String> loadTileSpecs(Context context, String tileList) {
final Resources res = context.getResources();
final String defaultTileList = res.getString(R.string.quick_settings_tiles_default);
if (tileList == null) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java
index 8f329c4..f3aba4f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java
@@ -68,7 +68,7 @@
private ViewGroup mDateTimeAlarmGroup;
private TextView mEmergencyOnly;
- private ExpandableIndicator mExpandIndicator;
+ protected ExpandableIndicator mExpandIndicator;
private boolean mListening;
private AlarmManager.AlarmClockInfo mNextAlarm;
@@ -124,7 +124,6 @@
// 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);
updateResources();
@@ -136,6 +135,12 @@
updateResources();
}
+ @Override
+ public void onRtlPropertiesChanged(int layoutDirection) {
+ super.onRtlPropertiesChanged(layoutDirection);
+ updateResources();
+ }
+
private void updateResources() {
FontSizeUtils.updateFontSize(mAlarmStatus, R.dimen.qs_date_collapsed_size);
FontSizeUtils.updateFontSize(mEmergencyOnly, R.dimen.qs_emergency_calls_only_text_size);
@@ -175,6 +180,20 @@
.addFloat(mMultiUserSwitch, "alpha", 0, 1)
.setStartDelay(QSAnimator.EXPANDED_TILE_DELAY)
.build();
+
+ final boolean isRtl = isLayoutRtl();
+ if (isRtl && mDateTimeGroup.getWidth() == 0) {
+ mDateTimeGroup.addOnLayoutChangeListener(new OnLayoutChangeListener() {
+ @Override
+ public void onLayoutChange(View v, int left, int top, int right, int bottom,
+ int oldLeft, int oldTop, int oldRight, int oldBottom) {
+ mDateTimeGroup.setPivotX(getWidth());
+ mDateTimeGroup.removeOnLayoutChangeListener(this);
+ }
+ });
+ } else {
+ mDateTimeGroup.setPivotX(isRtl ? mDateTimeGroup.getWidth() : 0);
+ }
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
index 95f26d4..6a2ecf4e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
@@ -654,7 +654,7 @@
}
@Override
- public void onMultiWindowChanged() {
+ public void onMultiWindowModeChanged() {
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java
index 0442ac3..2783ec5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java
@@ -37,22 +37,14 @@
super(context, theme);
mContext = context;
- getWindow().setType(WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL);
- getWindow().addFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM
- | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED);
+ applyFlags(this);
WindowManager.LayoutParams attrs = getWindow().getAttributes();
attrs.setTitle(getClass().getSimpleName());
getWindow().setAttributes(attrs);
}
public void setShowForAllUsers(boolean show) {
- if (show) {
- getWindow().getAttributes().privateFlags |=
- WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
- } else {
- getWindow().getAttributes().privateFlags &=
- ~WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
- }
+ setShowForAllUsers(this, show);
}
public void setMessage(int resId) {
@@ -66,4 +58,20 @@
public void setNegativeButton(int resId, OnClickListener onClick) {
setButton(BUTTON_NEGATIVE, mContext.getString(resId), onClick);
}
+
+ public static void setShowForAllUsers(AlertDialog dialog, boolean show) {
+ if (show) {
+ dialog.getWindow().getAttributes().privateFlags |=
+ WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
+ } else {
+ dialog.getWindow().getAttributes().privateFlags &=
+ ~WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
+ }
+ }
+
+ public static void applyFlags(AlertDialog dialog) {
+ dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL);
+ dialog.getWindow().addFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM
+ | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED);
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
index 1f4ef4a..557f166 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
@@ -121,8 +121,11 @@
mEditText.setEnabled(false);
mSendButton.setVisibility(INVISIBLE);
mProgressBar.setVisibility(VISIBLE);
+ mEntry.remoteInputText = mEditText.getText();
+ mController.addSpinning(mEntry.key);
mController.removeRemoteInput(mEntry);
mEditText.mShowImeOnInputConnection = false;
+ mController.remoteInputSent(mEntry);
try {
mPendingIntent.send(mContext, 0, fillInIntent);
@@ -177,6 +180,7 @@
return;
}
mController.removeRemoteInput(mEntry);
+ mController.removeSpinning(mEntry.key);
}
public void setPendingIntent(PendingIntent pendingIntent) {
@@ -213,6 +217,7 @@
mEditText.setEnabled(true);
mSendButton.setVisibility(VISIBLE);
mProgressBar.setVisibility(INVISIBLE);
+ mController.removeSpinning(mEntry.key);
updateSendButton();
onDefocus();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
index b5030e6..4a8abe6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -3532,7 +3532,8 @@
} else {
// Check scheduled, reset alpha and update location; check will fade it in
mCurrIconRow.setGearAlpha(0f);
- mCurrIconRow.setIconLocation(translation > 0 /* onLeft */);
+ mCurrIconRow.setIconLocation(translation > 0 /* onLeft */,
+ false /* force */);
}
}
}
@@ -3547,8 +3548,9 @@
}
@Override
- public void dismissChild(final View view, float velocity) {
- super.dismissChild(view, velocity);
+ public void dismissChild(final View view, float velocity,
+ boolean useAccelerateInterpolator) {
+ super.dismissChild(view, velocity, useAccelerateInterpolator);
cancelCheckForDrag();
setSnappedToGear(false);
}
@@ -3584,7 +3586,8 @@
snapChild(animView, 0 /* leftTarget */, velocity);
} else if (isDismissGesture(ev)) {
// Gesture is a dismiss that's not towards the gear
- dismissChild(animView, swipedFastEnough() ? velocity : 0f);
+ dismissChild(animView, velocity,
+ !swipedFastEnough() /* useAccelerateInterpolator */);
} else {
// Didn't move enough to dismiss or cover, snap to the gear
snapToGear(animView, velocity);
@@ -3609,7 +3612,8 @@
private void dismissOrSnapBack(View animView, float velocity, MotionEvent ev) {
if (isDismissGesture(ev)) {
- dismissChild(animView, swipedFastEnough() ? velocity : 0f);
+ dismissChild(animView, velocity,
+ !swipedFastEnough() /* useAccelerateInterpolator */);
} else {
snapChild(animView, 0 /* leftTarget */, velocity);
}
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/NightModeFragment.java b/packages/SystemUI/src/com/android/systemui/tuner/NightModeFragment.java
index 8c945f9..ae2856c 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/NightModeFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/NightModeFragment.java
@@ -43,7 +43,6 @@
public static final String EXTRA_SHOW_NIGHT_MODE = "show_night_mode";
private static final CharSequence KEY_AUTO = "auto";
- private static final CharSequence KEY_DARK_THEME = "dark_theme";
private static final CharSequence KEY_ADJUST_TINT = "adjust_tint";
private static final CharSequence KEY_ADJUST_BRIGHTNESS = "adjust_brightness";
@@ -51,7 +50,6 @@
private NightModeController mNightModeController;
private SwitchPreference mAutoSwitch;
- private SwitchPreference mDarkTheme;
private SwitchPreference mAdjustTint;
private SwitchPreference mAdjustBrightness;
private UiModeManager mUiModeManager;
@@ -79,8 +77,6 @@
addPreferencesFromResource(R.xml.night_mode);
mAutoSwitch = (SwitchPreference) findPreference(KEY_AUTO);
mAutoSwitch.setOnPreferenceChangeListener(this);
- mDarkTheme = (SwitchPreference) findPreference(KEY_DARK_THEME);
- mDarkTheme.setOnPreferenceChangeListener(this);
mAdjustTint = (SwitchPreference) findPreference(KEY_ADJUST_TINT);
mAdjustTint.setOnPreferenceChangeListener(this);
mAdjustBrightness = (SwitchPreference) findPreference(KEY_ADJUST_BRIGHTNESS);
@@ -111,7 +107,6 @@
mNightModeController.addListener(this);
TunerService.get(getContext()).addTunable(this, Secure.BRIGHTNESS_USE_TWILIGHT,
NightModeController.NIGHT_MODE_ADJUST_TINT);
- mDarkTheme.setChecked(mUiModeManager.getNightMode() == UiModeManager.MODE_NIGHT_AUTO);
calculateDisabled();
}
@@ -129,12 +124,6 @@
if (mAutoSwitch == preference) {
MetricsLogger.action(getContext(), MetricsEvent.ACTION_TUNER_NIGHT_MODE_AUTO, value);
mNightModeController.setAuto(value);
- } else if (mDarkTheme == preference) {
- MetricsLogger.action(getContext(),
- MetricsEvent.ACTION_TUNER_NIGHT_MODE_ADJUST_DARK_THEME, value);
- mUiModeManager.setNightMode(value ? UiModeManager.MODE_NIGHT_AUTO
- : UiModeManager.MODE_NIGHT_NO);
- postCalculateDisabled();
} else if (mAdjustTint == preference) {
MetricsLogger.action(getContext(),
MetricsEvent.ACTION_TUNER_NIGHT_MODE_ADJUST_TINT, value);
@@ -163,19 +152,15 @@
}
private void calculateDisabled() {
- int enabledCount = (mDarkTheme.isChecked() ? 1 : 0)
- + (mAdjustTint.isChecked() ? 1 : 0)
+ int enabledCount = (mAdjustTint.isChecked() ? 1 : 0)
+ (mAdjustBrightness.isChecked() ? 1 : 0);
if (enabledCount == 1) {
- if (mDarkTheme.isChecked()) {
- mDarkTheme.setEnabled(false);
- } else if (mAdjustTint.isChecked()) {
+ if (mAdjustTint.isChecked()) {
mAdjustTint.setEnabled(false);
} else {
mAdjustBrightness.setEnabled(false);
}
} else {
- mDarkTheme.setEnabled(true);
mAdjustTint.setEnabled(true);
mAdjustBrightness.setEnabled(true);
}
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/NightModeTile.java b/packages/SystemUI/src/com/android/systemui/tuner/NightModeTile.java
index 26e1d46..fe44502 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/NightModeTile.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/NightModeTile.java
@@ -15,10 +15,7 @@
*/
package com.android.systemui.tuner;
-import android.app.ActivityManager;
import android.content.Intent;
-import android.provider.Settings;
-
import com.android.internal.logging.MetricsProto.MetricsEvent;
import com.android.systemui.Prefs;
import com.android.systemui.Prefs.Key;
@@ -26,8 +23,6 @@
import com.android.systemui.qs.QSTile;
import com.android.systemui.statusbar.policy.NightModeController;
-import java.util.Objects;
-
public class NightModeTile extends QSTile<QSTile.State> implements NightModeController.Listener {
@@ -81,6 +76,11 @@
}
@Override
+ public CharSequence getTileLabel() {
+ return mContext.getString(R.string.night_mode);
+ }
+
+ @Override
protected void handleUpdateState(State state, Object arg) {
// TODO: Right now this is just a dropper, needs an actual night icon.
boolean enabled = mNightModeController.isEnabled();
diff --git a/packages/SystemUI/src/com/android/systemui/tv/pip/PipControlsView.java b/packages/SystemUI/src/com/android/systemui/tv/pip/PipControlsView.java
index 0e64dcd..3f87611 100644
--- a/packages/SystemUI/src/com/android/systemui/tv/pip/PipControlsView.java
+++ b/packages/SystemUI/src/com/android/systemui/tv/pip/PipControlsView.java
@@ -16,11 +16,12 @@
package com.android.systemui.tv.pip;
-import android.app.Activity;
import android.content.Context;
import android.media.session.MediaController;
import android.media.session.PlaybackState;
import android.view.View;
+import android.view.Gravity;
+import android.view.LayoutInflater;
import android.view.View.OnFocusChangeListener;
import android.widget.ImageView;
import android.widget.TextView;
@@ -40,28 +41,29 @@
/**
* A view containing PIP controls including fullscreen, close, and media controls.
*/
-public class PipControlsView extends LinearLayout implements PipManager.Listener {
+public class PipControlsView extends LinearLayout {
/**
* An interface to listen user action.
*/
- public interface Listener {
+ public abstract static interface Listener {
/**
* Called when an user clicks close PIP button.
*/
- void onClosed();
- }
+ public abstract void onClosed();
+ };
- private final PipManager mPipManager = PipManager.getInstance();
private MediaController mMediaController;
- private Listener mListener;
- private View mFullButtonView;
- private View mFullDescriptionView;
- private View mPlayPauseView;
- private ImageView mPlayPauseButtonImageView;
- private TextView mPlayPauseDescriptionTextView;
- private View mCloseButtonView;
- private View mCloseDescriptionView;
+ final PipManager mPipManager = PipManager.getInstance();
+ Listener mListener;
+
+ View mFullButtonView;
+ View mFullDescriptionView;
+ View mPlayPauseView;
+ ImageView mPlayPauseButtonImageView;
+ TextView mPlayPauseDescriptionTextView;
+ View mCloseButtonView;
+ View mCloseDescriptionView;
private boolean mHasFocus;
private OnFocusChangeListener mOnChildFocusChangeListener;
@@ -73,6 +75,13 @@
}
};
+ private PipManager.MediaListener mPipMediaListener = new PipManager.MediaListener() {
+ @Override
+ public void onMediaControllerChanged() {
+ updateMediaController();
+ }
+ };
+
public PipControlsView(Context context) {
this(context, null, 0, 0);
}
@@ -87,6 +96,12 @@
public PipControlsView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
+ LayoutInflater inflater = (LayoutInflater) getContext()
+ .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+ inflater.inflate(R.layout.tv_pip_controls, this);
+
+ setOrientation(LinearLayout.HORIZONTAL);
+ setGravity(Gravity.TOP | Gravity.CENTER_HORIZONTAL);
}
@Override
@@ -143,7 +158,9 @@
@Override
public void onClick(View v) {
mPipManager.closePip();
- mListener.onClosed();
+ if (mListener != null) {
+ mListener.onClosed();
+ }
}
});
mCloseButtonView.setOnFocusChangeListener(new View.OnFocusChangeListener() {
@@ -159,13 +176,13 @@
public void onAttachedToWindow() {
super.onAttachedToWindow();
updateMediaController();
- mPipManager.addListener(this);
+ mPipManager.addMediaListener(mPipMediaListener);
}
@Override
public void onDetachedFromWindow() {
super.onDetachedFromWindow();
- mPipManager.removeListener(this);
+ mPipManager.removeMediaListener(mPipMediaListener);
if (mMediaController != null) {
mMediaController.unregisterCallback(mMediaControllerCallback);
}
@@ -228,24 +245,4 @@
public void setListener(Listener listener) {
mListener = listener;
}
-
- @Override
- public void onPipEntered() { }
-
- @Override
- public void onPipActivityClosed() { }
-
- @Override
- public void onShowPipMenu() { }
-
- @Override
- public void onMoveToFullscreen() { }
-
- @Override
- public void onMediaControllerChanged() {
- updateMediaController();
- }
-
- @Override
- public void onPipResizeAboutToStart() { }
}
diff --git a/packages/SystemUI/src/com/android/systemui/tv/pip/PipManager.java b/packages/SystemUI/src/com/android/systemui/tv/pip/PipManager.java
index 68e0883..b5c1f57 100644
--- a/packages/SystemUI/src/com/android/systemui/tv/pip/PipManager.java
+++ b/packages/SystemUI/src/com/android/systemui/tv/pip/PipManager.java
@@ -62,9 +62,27 @@
private static final int MAX_RUNNING_TASKS_COUNT = 10;
+ /**
+ * State when there's no PIP.
+ */
public static final int STATE_NO_PIP = 0;
+ /**
+ * State when PIP is shown with an overlay message on top of it.
+ * This is used as default PIP state.
+ */
public static final int STATE_PIP_OVERLAY = 1;
+ /**
+ * State when PIP menu dialog is shown.
+ */
public static final int STATE_PIP_MENU = 2;
+ /**
+ * State when PIP is shown in Recents.
+ */
+ public static final int STATE_PIP_RECENTS = 3;
+ /**
+ * State when PIP is shown in Recents and it's focused to allow an user to control.
+ */
+ public static final int STATE_PIP_RECENTS_FOCUSED = 4;
private static final int TASK_ID_NO_PIP = -1;
private static final int INVALID_RESOURCE_TYPE = -1;
@@ -90,11 +108,13 @@
private int mSuspendPipResizingReason;
private Context mContext;
+ private PipRecentsOverlayManager mPipRecentsOverlayManager;
private IActivityManager mActivityManager;
private MediaSessionManager mMediaSessionManager;
private int mState = STATE_NO_PIP;
private final Handler mHandler = new Handler();
private List<Listener> mListeners = new ArrayList<>();
+ private List<MediaListener> mMediaListeners = new ArrayList<>();
private Rect mCurrentPipBounds;
private Rect mPipBounds;
private Rect mMenuModePipBounds;
@@ -107,9 +127,6 @@
private MediaController mPipMediaController;
private boolean mOnboardingShown;
- private boolean mIsRecentsShown;
- private boolean mIsPipFocusedInRecent;
-
private final Runnable mResizePinnedStackRunnable = new Runnable() {
@Override
public void run() {
@@ -178,6 +195,7 @@
mOnboardingShown = Prefs.getBoolean(
mContext, TV_PICTURE_IN_PICTURE_ONBOARDING_SHOWN, false);
+ mPipRecentsOverlayManager = new PipRecentsOverlayManager(context);
mMediaSessionManager =
(MediaSessionManager) mContext.getSystemService(Context.MEDIA_SESSION_SERVICE);
}
@@ -231,7 +249,7 @@
/**
* Moves the PIPed activity to the fullscreen and closes PIP system UI.
*/
- public void movePipToFullscreen() {
+ void movePipToFullscreen() {
mState = STATE_NO_PIP;
mPipTaskId = TASK_ID_NO_PIP;
for (int i = mListeners.size() - 1; i >= 0; --i) {
@@ -247,8 +265,11 @@
*/
private void showPipOverlay() {
if (DEBUG) Log.d(TAG, "showPipOverlay()");
- mState = STATE_PIP_OVERLAY;
- PipOverlayActivity.showPipOverlay(mContext);
+ Intent intent = new Intent(mContext, PipOverlayActivity.class);
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ final ActivityOptions options = ActivityOptions.makeBasic();
+ options.setLaunchStackId(PINNED_STACK_ID);
+ mContext.startActivity(intent, options.toBundle());
}
/**
@@ -279,8 +300,10 @@
* Resize the Pip to the appropriate size for the input state.
* @param state In Pip state also used to determine the new size for the Pip.
*/
- public void resizePinnedStack(int state) {
+ void resizePinnedStack(int state) {
if (DEBUG) Log.d(TAG, "resizePinnedStack() state=" + state);
+ boolean wasRecentsShown =
+ (mState == STATE_PIP_RECENTS || mState == STATE_PIP_RECENTS_FOCUSED);
mState = state;
for (int i = mListeners.size() - 1; i >= 0; --i) {
mListeners.get(i).onPipResizeAboutToStart();
@@ -291,7 +314,6 @@
mSuspendPipResizingReason);
return;
}
- int animationDurationMs = -1;
switch (mState) {
case STATE_NO_PIP:
mCurrentPipBounds = null;
@@ -300,25 +322,24 @@
mCurrentPipBounds = mMenuModePipBounds;
break;
case STATE_PIP_OVERLAY:
- if (mIsRecentsShown) {
- if (mCurrentPipBounds == mRecentsFocusedPipBounds
- || mCurrentPipBounds == mRecentsFocusedPipBounds) {
- animationDurationMs = mRecentsFocusChangedAnimationDurationMs;
- }
- if (mIsPipFocusedInRecent) {
- mCurrentPipBounds = mRecentsFocusedPipBounds;
- } else {
- mCurrentPipBounds = mRecentsPipBounds;
- }
- } else {
- mCurrentPipBounds = mPipBounds;
- }
+ mCurrentPipBounds = mPipBounds;
+ break;
+ case STATE_PIP_RECENTS:
+ mCurrentPipBounds = mRecentsPipBounds;
+ break;
+ case STATE_PIP_RECENTS_FOCUSED:
+ mCurrentPipBounds = mRecentsFocusedPipBounds;
break;
default:
mCurrentPipBounds = mPipBounds;
break;
}
try {
+ int animationDurationMs = -1;
+ if (wasRecentsShown
+ && (mState == STATE_PIP_RECENTS || mState == STATE_PIP_RECENTS_FOCUSED)) {
+ animationDurationMs = mRecentsFocusChangedAnimationDurationMs;
+ }
mActivityManager.resizeStack(PINNED_STACK_ID, mCurrentPipBounds,
true, true, true, animationDurationMs);
} catch (RemoteException e) {
@@ -327,67 +348,18 @@
}
/**
- * Returns the current PIP bound for activities to sync their UI with PIP.
+ * Returns the default PIP bound.
*/
public Rect getPipBounds() {
- return mCurrentPipBounds;
+ return mPipBounds;
}
/**
- * Called when Recents is started.
- * PIPed activity will be resized accordingly and overlay will show available buttons.
+ * Returns the focused PIP bound while Recents is shown.
+ * This is used to place PIP controls in Recents.
*/
- public void onRecentsStarted() {
- mIsRecentsShown = true;
- mIsPipFocusedInRecent = false;
- if (mState == STATE_NO_PIP) {
- return;
- }
- resizePinnedStack(STATE_PIP_OVERLAY);
- }
-
- /**
- * Called when Recents is stopped.
- * PIPed activity will be resized accordingly and overlay will hide available buttons.
- */
- public void onRecentsStopped() {
- mIsRecentsShown = false;
- mIsPipFocusedInRecent = false;
- if (mState == STATE_NO_PIP) {
- return;
- }
- resizePinnedStack(STATE_PIP_OVERLAY);
- }
-
- /**
- * Returns {@code true} if recents is shown.
- */
- boolean isRecentsShown() {
- return mIsRecentsShown;
- }
-
- /**
- * Called when the PIP view in {@link com.android.systemui.recents.tv.RecentsTvActivity}
- * is focused.
- * This only resizes pinned stack so it looks like it's in Recents.
- * This should be called only by {@link com.android.systemui.recents.tv.RecentsTvActivity}.
- */
- public void onPipViewFocusChangedInRecents(boolean hasFocus) {
- mIsPipFocusedInRecent = hasFocus;
- if (mState != STATE_PIP_OVERLAY) {
- Log.w(TAG, "There is no pinned stack to handle focus change.");
- return;
- }
- resizePinnedStack(STATE_PIP_OVERLAY);
- }
-
- /**
- * Returns {@code true} if the PIP view in
- * {@link com.android.systemui.recents.tv.RecentsTvActivity} is focused in Recents.
- * This API is valid only when {@link isRecentsShown()} returns {@code true}.
- */
- boolean isPipViewFocusdInRecents() {
- return mIsPipFocusedInRecent;
+ public Rect getRecentsFocusedPipBounds() {
+ return mRecentsFocusedPipBounds;
}
/**
@@ -396,6 +368,10 @@
*/
private void showPipMenu() {
if (DEBUG) Log.d(TAG, "showPipMenu()");
+ if (mPipRecentsOverlayManager.isRecentsShown()) {
+ if (DEBUG) Log.d(TAG, "Ignore showing PIP menu");
+ return;
+ }
mState = STATE_PIP_MENU;
for (int i = mListeners.size() - 1; i >= 0; --i) {
mListeners.get(i).onShowPipMenu();
@@ -405,14 +381,34 @@
mContext.startActivity(intent);
}
+ /**
+ * Adds a {@link Listener} to PipManager.
+ */
public void addListener(Listener listener) {
mListeners.add(listener);
}
+ /**
+ * Removes a {@link Listener} from PipManager.
+ */
public void removeListener(Listener listener) {
mListeners.remove(listener);
}
+ /**
+ * Adds a {@link MediaListener} to PipManager.
+ */
+ public void addMediaListener(MediaListener listener) {
+ mMediaListeners.add(listener);
+ }
+
+ /**
+ * Removes a {@link MediaListener} from PipManager.
+ */
+ public void removeMediaListener(MediaListener listener) {
+ mMediaListeners.remove(listener);
+ }
+
private void launchPipOnboardingActivityIfNeeded() {
if (DEBUG_FORCE_ONBOARDING || !mOnboardingShown) {
mOnboardingShown = true;
@@ -485,8 +481,8 @@
}
if (mPipMediaController != mediaController) {
mPipMediaController = mediaController;
- for (int i = mListeners.size() - 1; i >= 0; i--) {
- mListeners.get(i).onMediaControllerChanged();
+ for (int i = mMediaListeners.size() - 1; i >= 0; i--) {
+ mMediaListeners.get(i).onMediaControllerChanged();
}
if (mPipMediaController == null) {
mHandler.postDelayed(mClosePipRunnable,
@@ -530,7 +526,7 @@
return PLAYBACK_STATE_UNAVAILABLE;
}
- TaskStackListener mTaskStackListener = new TaskStackListener() {
+ private TaskStackListener mTaskStackListener = new TaskStackListener() {
@Override
public void onTaskStackChanged() {
if (mState != STATE_NO_PIP) {
@@ -582,10 +578,10 @@
mMediaSessionManager.addOnActiveSessionsChangedListener(
mActiveMediaSessionListener, null);
updateMediaController(mMediaSessionManager.getActiveSessions(null));
- if (mIsRecentsShown) {
+ if (mPipRecentsOverlayManager.isRecentsShown()) {
// If an activity becomes PIPed again after the fullscreen, the Recents is shown
// behind so we need to resize the pinned stack and show the correct overlay.
- resizePinnedStack(STATE_PIP_OVERLAY);
+ resizePinnedStack(STATE_PIP_RECENTS);
}
for (int i = mListeners.size() - 1; i >= 0; i--) {
mListeners.get(i).onPipEntered();
@@ -604,7 +600,18 @@
if (DEBUG) Log.d(TAG, "onPinnedStackAnimationEnded()");
switch (mState) {
case STATE_PIP_OVERLAY:
- showPipOverlay();
+ if (!mPipRecentsOverlayManager.isRecentsShown()) {
+ showPipOverlay();
+ break;
+ } else {
+ // This happens only if an activity is PIPed after the Recents is shown.
+ // See {@link PipRecentsOverlayManager.requestFocus} for more details.
+ resizePinnedStack(mState);
+ break;
+ }
+ case STATE_PIP_RECENTS:
+ case STATE_PIP_RECENTS_FOCUSED:
+ mPipRecentsOverlayManager.addPipRecentsOverlayView();
break;
case STATE_PIP_MENU:
showPipMenu();
@@ -621,7 +628,7 @@
* Invoked when an activity is pinned and PIP manager is set corresponding information.
* Classes must use this instead of {@link android.app.ITaskStackListener.onActivityPinned}
* because there's no guarantee for the PIP manager be return relavent information
- * correctly. (e.g. {@link isPipShown}, {@link getPipBounds})
+ * correctly. (e.g. {@link isPipShown}).
*/
void onPipEntered();
/** Invoked when a PIPed activity is closed. */
@@ -632,6 +639,12 @@
void onMoveToFullscreen();
/** Invoked when we are above to start resizing the Pip. */
void onPipResizeAboutToStart();
+ }
+
+ /**
+ * A listener interface to receive change in PIP's media controller
+ */
+ public interface MediaListener {
/** Invoked when the MediaController on PIPed activity is changed. */
void onMediaControllerChanged();
}
@@ -645,4 +658,11 @@
}
return sPipManager;
}
+
+ /**
+ * Gets an instance of {@link PipRecentsOverlayManager}.
+ */
+ public PipRecentsOverlayManager getPipRecentsOverlayManager() {
+ return mPipRecentsOverlayManager;
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/tv/pip/PipMenuActivity.java b/packages/SystemUI/src/com/android/systemui/tv/pip/PipMenuActivity.java
index ea9275f..c54e73a 100644
--- a/packages/SystemUI/src/com/android/systemui/tv/pip/PipMenuActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/tv/pip/PipMenuActivity.java
@@ -20,12 +20,6 @@
import android.os.Bundle;
import com.android.systemui.R;
-import com.android.systemui.SystemUI;
-import com.android.systemui.SystemUIApplication;
-import com.android.systemui.recents.Recents;
-
-import static android.content.pm.PackageManager.FEATURE_LEANBACK;
-import static android.content.pm.PackageManager.FEATURE_PICTURE_IN_PICTURE;
/**
* Activity to show the PIP menu to control PIP.
@@ -36,7 +30,6 @@
private final PipManager mPipManager = PipManager.getInstance();
private PipControlsView mPipControlsView;
- private boolean mPipMovedToFullscreen;
@Override
protected void onCreate(Bundle bundle) {
@@ -47,17 +40,10 @@
mPipControlsView = (PipControlsView) findViewById(R.id.pip_controls);
}
- private void restorePipAndFinish() {
- if (!mPipMovedToFullscreen) {
- mPipManager.resizePinnedStack(PipManager.STATE_PIP_OVERLAY);
- }
- finish();
- }
-
@Override
public void onPause() {
super.onPause();
- restorePipAndFinish();
+ finish();
}
@Override
@@ -69,11 +55,6 @@
}
@Override
- public void onBackPressed() {
- restorePipAndFinish();
- }
-
- @Override
public void onPipEntered() { }
@Override
@@ -86,31 +67,13 @@
@Override
public void onMoveToFullscreen() {
- mPipMovedToFullscreen = true;
finish();
}
@Override
- public void onMediaControllerChanged() { }
-
- @Override
public void onPipResizeAboutToStart() {
finish();
mPipManager.suspendPipResizing(
PipManager.SUSPEND_PIP_RESIZE_REASON_WAITING_FOR_MENU_ACTIVITY_FINISH);
}
-
- @Override
- public void finish() {
- super.finish();
- if (mPipManager.isRecentsShown() && !mPipMovedToFullscreen) {
- SystemUI[] services = ((SystemUIApplication) getApplication()).getServices();
- for (int i = services.length - 1; i >= 0; i--) {
- if (services[i] instanceof Recents) {
- ((Recents) services[i]).showRecents(false, null);
- break;
- }
- }
- }
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/tv/pip/PipOnboardingActivity.java b/packages/SystemUI/src/com/android/systemui/tv/pip/PipOnboardingActivity.java
index 79daf3d..86ceff4 100644
--- a/packages/SystemUI/src/com/android/systemui/tv/pip/PipOnboardingActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/tv/pip/PipOnboardingActivity.java
@@ -86,7 +86,4 @@
@Override
public void onPipResizeAboutToStart() { }
-
- @Override
- public void onMediaControllerChanged() { }
}
diff --git a/packages/SystemUI/src/com/android/systemui/tv/pip/PipOverlayActivity.java b/packages/SystemUI/src/com/android/systemui/tv/pip/PipOverlayActivity.java
index 12cb4cd..5472ad6 100644
--- a/packages/SystemUI/src/com/android/systemui/tv/pip/PipOverlayActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/tv/pip/PipOverlayActivity.java
@@ -35,14 +35,6 @@
public class PipOverlayActivity extends Activity implements PipManager.Listener {
private static final long SHOW_GUIDE_OVERLAY_VIEW_DURATION_MS = 4000;
- /**
- * The single instance of PipOverlayActivity to prevent it from restarting.
- * Note that {@link PipManager} moves the PIPed activity to fullscreen if the activity is
- * restarted. It's because the activity may be started by the Launcher or an intent again,
- * but we don't want do so for the PipOverlayActivity.
- */
- private static PipOverlayActivity sPipOverlayActivity;
-
private final PipManager mPipManager = PipManager.getInstance();
private final Handler mHandler = new Handler();
private View mGuideOverlayView;
@@ -54,47 +46,17 @@
}
};
- /**
- * Launches the PIP overlay. This should be only called on the main thread.
- */
- public static void showPipOverlay(Context context) {
- if (sPipOverlayActivity == null) {
- Intent intent = new Intent(context, PipOverlayActivity.class);
- intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- final ActivityOptions options = ActivityOptions.makeBasic();
- options.setLaunchStackId(PINNED_STACK_ID);
- context.startActivity(intent, options.toBundle());
- }
- }
-
@Override
protected void onCreate(Bundle bundle) {
super.onCreate(bundle);
setContentView(R.layout.tv_pip_overlay);
mGuideOverlayView = findViewById(R.id.guide_overlay);
- mGuideButtonsView = findViewById(R.id.guide_buttons);
- mGuideButtonPlayPauseImageView = (ImageView) findViewById(R.id.guide_button_play_pause);
mPipManager.addListener(this);
-
- sPipOverlayActivity = this;
}
@Override
protected void onResume() {
super.onResume();
- // TODO: Implement animation for this
- if (mPipManager.isRecentsShown()) {
- mGuideOverlayView.setVisibility(View.GONE);
- if (mPipManager.isPipViewFocusdInRecents()) {
- mGuideButtonsView.setVisibility(View.GONE);
- } else {
- mGuideButtonsView.setVisibility(View.VISIBLE);
- updateGuideButtonsView();
- }
- } else {
- mGuideOverlayView.setVisibility(View.VISIBLE);
- mGuideButtonsView.setVisibility(View.GONE);
- }
mHandler.removeCallbacks(mHideGuideOverlayRunnable);
mHandler.postDelayed(mHideGuideOverlayRunnable, SHOW_GUIDE_OVERLAY_VIEW_DURATION_MS);
}
@@ -109,7 +71,6 @@
@Override
protected void onDestroy() {
super.onDestroy();
- sPipOverlayActivity = null;
mHandler.removeCallbacksAndMessages(null);
mPipManager.removeListener(this);
mPipManager.resumePipResizing(
@@ -140,32 +101,4 @@
mPipManager.suspendPipResizing(
PipManager.SUSPEND_PIP_RESIZE_REASON_WAITING_FOR_OVERLAY_ACTIVITY_FINISH);
}
-
- @Override
- public void onMediaControllerChanged() {
- updateGuideButtonsView();
- }
-
- @Override
- public void finish() {
- sPipOverlayActivity = null;
- super.finish();
- }
-
- private void updateGuideButtonsView() {
- switch (mPipManager.getPlaybackState()) {
- case PipManager.PLAYBACK_STATE_PLAYING:
- mGuideButtonPlayPauseImageView.setVisibility(View.VISIBLE);
- mGuideButtonPlayPauseImageView.setImageResource(R.drawable.ic_pause_white_24dp);
- break;
- case PipManager.PLAYBACK_STATE_PAUSED:
- mGuideButtonPlayPauseImageView.setVisibility(View.VISIBLE);
- mGuideButtonPlayPauseImageView.setImageResource(
- R.drawable.ic_play_arrow_white_24dp);
- break;
- case PipManager.PLAYBACK_STATE_UNAVAILABLE:
- mGuideButtonPlayPauseImageView.setVisibility(View.GONE);
- break;
- }
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/tv/pip/PipRecentsControlsView.java b/packages/SystemUI/src/com/android/systemui/tv/pip/PipRecentsControlsView.java
new file mode 100644
index 0000000..8b8c105
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/tv/pip/PipRecentsControlsView.java
@@ -0,0 +1,169 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.tv.pip;
+
+import android.animation.Animator;
+import android.animation.AnimatorInflater;
+import android.animation.AnimatorSet;
+import android.content.Context;
+import android.graphics.Rect;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.KeyEvent;
+import android.view.View;
+import android.view.View.OnFocusChangeListener;
+
+import com.android.systemui.R;
+
+import static com.android.systemui.tv.pip.PipManager.PLAYBACK_STATE_PLAYING;
+import static com.android.systemui.tv.pip.PipManager.PLAYBACK_STATE_PAUSED;
+import static com.android.systemui.tv.pip.PipManager.PLAYBACK_STATE_UNAVAILABLE;
+
+/**
+ * An extended version of {@link PipControlsView} that supports animation in Recents.
+ */
+public class PipRecentsControlsView extends PipControlsView {
+ /**
+ * An interface to listen user action.
+ */
+ public interface Listener extends PipControlsView.Listener {
+ /**
+ * Called when an user presses BACK key and up.
+ */
+ abstract void onBackPressed();
+ }
+
+ private AnimatorSet mFocusGainAnimatorSet;
+ private AnimatorSet mFocusLoseAnimatorSet;
+
+ public PipRecentsControlsView(Context context) {
+ this(context, null, 0, 0);
+ }
+
+ public PipRecentsControlsView(Context context, AttributeSet attrs) {
+ this(context, attrs, 0, 0);
+ }
+
+ public PipRecentsControlsView(Context context, AttributeSet attrs, int defStyleAttr) {
+ this(context, attrs, defStyleAttr, 0);
+ }
+
+ public PipRecentsControlsView(
+ Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
+ }
+
+ @Override
+ public void onFinishInflate() {
+ super.onFinishInflate();
+
+ int buttonsFocusGainAnim = R.anim.tv_pip_controls_buttons_in_recents_focus_gain_animation;
+ int textFocusGainAnim = R.anim.tv_pip_controls_text_in_recents_focus_gain_animation;
+ mFocusGainAnimatorSet = new AnimatorSet();
+ mFocusGainAnimatorSet.playTogether(
+ loadAnimator(this, R.anim.tv_pip_controls_in_recents_focus_gain_animation),
+ loadAnimator(mFullButtonView,buttonsFocusGainAnim),
+ loadAnimator(mPlayPauseButtonImageView, buttonsFocusGainAnim),
+ loadAnimator(mCloseButtonView, buttonsFocusGainAnim),
+ loadAnimator(mFullDescriptionView, textFocusGainAnim),
+ loadAnimator(mPlayPauseDescriptionTextView, textFocusGainAnim),
+ loadAnimator(mCloseDescriptionView, textFocusGainAnim));
+
+ int buttonsFocusLoseAnim = R.anim.tv_pip_controls_buttons_in_recents_focus_lose_animation;
+ int textFocusLoseAnim = R.anim.tv_pip_controls_text_in_recents_focus_lose_animation;
+ mFocusLoseAnimatorSet = new AnimatorSet();
+ mFocusLoseAnimatorSet.playTogether(
+ loadAnimator(this, R.anim.tv_pip_controls_in_recents_focus_lose_animation),
+ loadAnimator(mFullButtonView, buttonsFocusLoseAnim),
+ loadAnimator(mPlayPauseButtonImageView, buttonsFocusLoseAnim),
+ loadAnimator(mCloseButtonView, buttonsFocusLoseAnim),
+ loadAnimator(mFullDescriptionView, textFocusLoseAnim),
+ loadAnimator(mPlayPauseDescriptionTextView, textFocusLoseAnim),
+ loadAnimator(mCloseDescriptionView, textFocusLoseAnim));
+
+ Rect pipBounds = mPipManager.getRecentsFocusedPipBounds();
+ int pipControlsMarginTop = getContext().getResources().getDimensionPixelSize(
+ R.dimen.recents_tv_pip_controls_margin_top);
+ setPadding(0, pipBounds.bottom + pipControlsMarginTop, 0, 0);
+ }
+
+ private Animator loadAnimator(View view, int animatorResId) {
+ Animator animator = AnimatorInflater.loadAnimator(getContext(), animatorResId);
+ animator.setTarget(view);
+ return animator;
+ }
+
+ /**
+ * Starts focus gaining animation.
+ */
+ public void startFocusGainAnimation() {
+ if (mFocusLoseAnimatorSet.isStarted()) {
+ mFocusLoseAnimatorSet.cancel();
+ }
+ mFocusGainAnimatorSet.start();
+ }
+
+ /**
+ * Starts focus losing animation.
+ */
+ public void startFocusLoseAnimation() {
+ if (mFocusGainAnimatorSet.isStarted()) {
+ mFocusGainAnimatorSet.cancel();
+ }
+ mFocusLoseAnimatorSet.start();
+ }
+
+ /**
+ * Resets the view to the initial state. (i.e. end of the focus gain)
+ */
+ public void reset() {
+ if (mFocusGainAnimatorSet.isStarted()) {
+ mFocusGainAnimatorSet.cancel();
+ }
+ if (mFocusLoseAnimatorSet.isStarted()) {
+ mFocusLoseAnimatorSet.cancel();
+ }
+
+ // Reset to initial state (i.e. end of focused)
+ requestFocus();
+ setTranslationY(0);
+ setScaleXY(mFullButtonView, 1);
+ setScaleXY(mPlayPauseButtonImageView, 1);
+ setScaleXY(mCloseButtonView, 1);
+ mFullDescriptionView.setAlpha(1);
+ mPlayPauseDescriptionTextView.setAlpha(1);
+ mCloseDescriptionView.setAlpha(1);
+ }
+
+ private void setScaleXY(View view, float scale) {
+ view.setScaleX(scale);
+ view.setScaleY(scale);
+ }
+
+ @Override
+ public boolean dispatchKeyEvent(KeyEvent event) {
+ if (!event.isCanceled()
+ && event.getKeyCode() == KeyEvent.KEYCODE_BACK
+ && event.getAction() == KeyEvent.ACTION_UP) {
+ if (mListener != null) {
+ ((PipRecentsControlsView.Listener) mListener).onBackPressed();
+ }
+ return true;
+ }
+ return super.dispatchKeyEvent(event);
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/tv/pip/PipRecentsOverlayManager.java b/packages/SystemUI/src/com/android/systemui/tv/pip/PipRecentsOverlayManager.java
new file mode 100644
index 0000000..b90b727
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/tv/pip/PipRecentsOverlayManager.java
@@ -0,0 +1,207 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.tv.pip;
+
+import android.animation.AnimatorInflater;
+import android.animation.AnimatorSet;
+import android.content.Context;
+import android.graphics.PixelFormat;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.WindowManager.LayoutParams;
+import android.view.WindowManager;
+
+import com.android.systemui.R;
+
+import static com.android.systemui.tv.pip.PipManager.STATE_PIP_OVERLAY;
+import static com.android.systemui.tv.pip.PipManager.STATE_PIP_RECENTS;
+import static com.android.systemui.tv.pip.PipManager.STATE_PIP_RECENTS_FOCUSED;
+
+public class PipRecentsOverlayManager {
+ private static final String TAG = "PipRecentsOverlayManager";
+
+ public interface Callback {
+ void onClosed();
+ void onBackPressed();
+ void onRecentsFocused();
+ }
+
+ private final PipManager mPipManager = PipManager.getInstance();
+ private final WindowManager mWindowManager;
+ private final View mOverlayView;
+ private final PipRecentsControlsView mPipControlsView;
+ private final View mRecentsView;
+
+ private final LayoutParams mPipRecentsControlsViewLayoutParams;
+ private final LayoutParams mPipRecentsControlsViewFocusedLayoutParams;
+
+ private boolean mIsPipRecentsOverlayShown;
+ private boolean mIsRecentsShown;
+ private boolean mIsPipFocusedInRecent;
+ private Callback mCallback;
+ private PipRecentsControlsView.Listener mPipControlsViewListener =
+ new PipRecentsControlsView.Listener() {
+ @Override
+ public void onClosed() {
+ if (mCallback != null) {
+ mCallback.onClosed();
+ }
+ }
+
+ @Override
+ public void onBackPressed() {
+ if (mCallback != null) {
+ mCallback.onBackPressed();
+ }
+ }
+ };
+
+ PipRecentsOverlayManager(Context context) {
+ mWindowManager = (WindowManager) context.getSystemService(WindowManager.class);
+
+ LayoutInflater inflater = (LayoutInflater) context
+ .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+ mOverlayView = inflater.inflate(R.layout.tv_pip_recents_overlay, null);
+ mPipControlsView = (PipRecentsControlsView) mOverlayView.findViewById(R.id.pip_controls);
+ mRecentsView = mOverlayView.findViewById(R.id.recents);
+ mRecentsView.setOnFocusChangeListener(new View.OnFocusChangeListener() {
+ @Override
+ public void onFocusChange(View v, boolean hasFocus) {
+ if (hasFocus) {
+ clearFocus();
+ }
+ }
+ });
+
+ mPipRecentsControlsViewLayoutParams = new WindowManager.LayoutParams(
+ LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT,
+ LayoutParams.TYPE_SYSTEM_DIALOG,
+ LayoutParams.FLAG_NOT_FOCUSABLE | LayoutParams.FLAG_NOT_TOUCHABLE,
+ PixelFormat.TRANSLUCENT);
+ mPipRecentsControlsViewFocusedLayoutParams = new WindowManager.LayoutParams(
+ LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT,
+ LayoutParams.TYPE_SYSTEM_DIALOG,
+ 0,
+ PixelFormat.TRANSLUCENT);
+ }
+
+ /**
+ * Add Recents overlay view.
+ * This is expected to be called after the PIP animation is over.
+ */
+ void addPipRecentsOverlayView() {
+ if (mIsPipRecentsOverlayShown) {
+ return;
+ }
+ mIsPipRecentsOverlayShown = true;
+ mIsPipFocusedInRecent = true;
+ mPipControlsView.reset();
+ mWindowManager.addView(mOverlayView, mPipRecentsControlsViewFocusedLayoutParams);
+ }
+
+ /**
+ * Remove Recents overlay view.
+ * This should be called when Recents or PIP is closed.
+ */
+ public void removePipRecentsOverlayView() {
+ if (!mIsPipRecentsOverlayShown) {
+ return;
+ }
+ mWindowManager.removeView(mOverlayView);
+ mIsPipRecentsOverlayShown = false;
+ }
+
+ /**
+ * Request focus to the PIP Recents overlay.
+ * Called when the PIP view in {@link com.android.systemui.recents.tv.RecentsTvActivity}
+ * is focused.
+ * This should be called only by {@link com.android.systemui.recents.tv.RecentsTvActivity}.
+ * @param hasRecentsFocusable {@code true} if Recents can have focus. (i.e. Has a recent task)
+ */
+ public void requestFocus(boolean hasRecentsFocusable) {
+ if (!mIsRecentsShown || mIsPipFocusedInRecent) {
+ return;
+ }
+ mIsPipFocusedInRecent = true;
+ mPipManager.resizePinnedStack(STATE_PIP_RECENTS_FOCUSED);
+
+ mWindowManager.updateViewLayout(mOverlayView, mPipRecentsControlsViewFocusedLayoutParams);
+ mPipControlsView.requestFocus();
+ mPipControlsView.startFocusGainAnimation();
+ mRecentsView.setVisibility(hasRecentsFocusable ? View.VISIBLE : View.GONE);
+ }
+
+ /**
+ * Request focus to the PIP Recents overlay.
+ * Called when the PIP view in {@link com.android.systemui.recents.tv.RecentsTvActivity}
+ * is focused.
+ * This should be called only by {@link com.android.systemui.recents.tv.RecentsTvActivity}.
+ */
+ private void clearFocus() {
+ if (!mIsRecentsShown || !mIsPipFocusedInRecent) {
+ return;
+ }
+ mIsPipFocusedInRecent = false;
+ mPipManager.resizePinnedStack(STATE_PIP_RECENTS);
+ mWindowManager.updateViewLayout(mOverlayView, mPipRecentsControlsViewLayoutParams);
+ mPipControlsView.startFocusLoseAnimation();
+ if (mCallback != null) {
+ mCallback.onRecentsFocused();
+ }
+ }
+
+ public void setCallback(Callback listener) {
+ mCallback = listener;
+ mPipControlsView.setListener(mCallback != null ? mPipControlsViewListener : null);
+ }
+
+ /**
+ * Called when Recents is resumed.
+ * PIPed activity will be resized accordingly and overlay will show available buttons.
+ */
+ public void onRecentsResumed() {
+ if (!mPipManager.isPipShown()) {
+ return;
+ }
+ mIsRecentsShown = true;
+ mIsPipFocusedInRecent = true;
+ mPipManager.resizePinnedStack(STATE_PIP_RECENTS_FOCUSED);
+ // Overlay view will be added after the resize animation ends, if any.
+ }
+
+ /**
+ * Called when Recents is paused.
+ * PIPed activity will be resized accordingly and overlay will hide available buttons.
+ */
+ public void onRecentsPaused() {
+ mIsRecentsShown = false;
+ mIsPipFocusedInRecent = false;
+ removePipRecentsOverlayView();
+
+ if (mPipManager.isPipShown()) {
+ mPipManager.resizePinnedStack(STATE_PIP_OVERLAY);
+ }
+ }
+
+ /**
+ * Returns {@code true} if recents is shown.
+ */
+ boolean isRecentsShown() {
+ return mIsRecentsShown;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/SegmentedButtons.java b/packages/SystemUI/src/com/android/systemui/volume/SegmentedButtons.java
index f432808..c6e4356 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/SegmentedButtons.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/SegmentedButtons.java
@@ -35,11 +35,11 @@
private static final Typeface MEDIUM = Typeface.create("sans-serif-medium", Typeface.NORMAL);
private final Context mContext;
- private final LayoutInflater mInflater;
+ protected final LayoutInflater mInflater;
private final SpTexts mSpTexts;
private Callback mCallback;
- private Object mSelectedValue;
+ protected Object mSelectedValue;
public SegmentedButtons(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -65,13 +65,21 @@
final Object tag = c.getTag();
final boolean selected = Objects.equals(mSelectedValue, tag);
c.setSelected(selected);
- c.setTypeface(selected ? MEDIUM : REGULAR);
+ setSelectedStyle(c, selected);
}
fireOnSelected(fromClick);
}
+ protected void setSelectedStyle(TextView textView, boolean selected) {
+ textView.setTypeface(selected ? MEDIUM : REGULAR);
+ }
+
+ public Button inflateButton() {
+ return (Button) mInflater.inflate(R.layout.segmented_button, this, false);
+ }
+
public void addButton(int labelResId, int contentDescriptionResId, Object value) {
- final Button b = (Button) mInflater.inflate(R.layout.segmented_button, this, false);
+ final Button b = inflateButton();
b.setTag(LABEL_RES_KEY, labelResId);
b.setText(labelResId);
b.setContentDescription(getResources().getString(contentDescriptionResId));
diff --git a/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java b/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java
index 6976c0b..e3ed92c 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java
@@ -86,7 +86,7 @@
= new Intent(Settings.ACTION_ZEN_MODE_PRIORITY_SETTINGS);
private final Context mContext;
- private final LayoutInflater mInflater;
+ protected final LayoutInflater mInflater;
private final H mHandler = new H();
private final ZenPrefs mPrefs;
private final TransitionHelper mTransitionHelper = new TransitionHelper();
@@ -95,12 +95,12 @@
private String mTag = TAG + "/" + Integer.toHexString(System.identityHashCode(this));
- private SegmentedButtons mZenButtons;
+ protected SegmentedButtons mZenButtons;
private View mZenIntroduction;
private TextView mZenIntroductionMessage;
private View mZenIntroductionConfirm;
private TextView mZenIntroductionCustomize;
- private LinearLayout mZenConditions;
+ protected LinearLayout mZenConditions;
private TextView mZenAlarmWarning;
private Callback mCallback;
@@ -148,10 +148,7 @@
mTransitionHelper.dump(fd, pw, args);
}
- @Override
- protected void onFinishInflate() {
- super.onFinishInflate();
-
+ protected void createZenButtons() {
mZenButtons = (SegmentedButtons) findViewById(R.id.zen_buttons);
mZenButtons.addButton(R.string.interruption_level_none_twoline,
R.string.interruption_level_none_with_warning,
@@ -163,7 +160,12 @@
R.string.interruption_level_priority,
Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS);
mZenButtons.setCallback(mZenButtonsCallback);
+ }
+ @Override
+ protected void onFinishInflate() {
+ super.onFinishInflate();
+ createZenButtons();
mZenIntroduction = findViewById(R.id.zen_introduction);
mZenIntroductionMessage = (TextView) findViewById(R.id.zen_introduction_message);
mSpTexts.add(mZenIntroductionMessage);
@@ -302,14 +304,18 @@
}
}
+ protected void addZenConditions(int count) {
+ for (int i = 0; i < count; i++) {
+ mZenConditions.addView(mInflater.inflate(R.layout.zen_mode_condition, this, false));
+ }
+ }
+
public void init(ZenModeController controller) {
mController = controller;
mCountdownConditionSupported = mController.isCountdownConditionSupported();
final int countdownDelta = mCountdownConditionSupported ? COUNTDOWN_CONDITION_COUNT : 0;
final int minConditions = 1 /*forever*/ + countdownDelta;
- for (int i = 0; i < minConditions; i++) {
- mZenConditions.addView(mInflater.inflate(R.layout.zen_mode_condition, this, false));
- }
+ addZenConditions(minConditions);
mSessionZen = getSelectedZen(-1);
handleUpdateManualRule(mController.getManualRule());
if (DEBUG) Log.d(mTag, "init mExitCondition=" + mExitCondition);
@@ -917,7 +923,7 @@
}
}
- private final SegmentedButtons.Callback mZenButtonsCallback = new SegmentedButtons.Callback() {
+ protected final SegmentedButtons.Callback mZenButtonsCallback = new SegmentedButtons.Callback() {
@Override
public void onSelected(final Object value, boolean fromClick) {
if (value != null && mZenButtons.isShown() && isAttachedToWindow()) {
diff --git a/packages/SystemUI/tests/AndroidManifest.xml b/packages/SystemUI/tests/AndroidManifest.xml
index 5389c804..53a9976 100644
--- a/packages/SystemUI/tests/AndroidManifest.xml
+++ b/packages/SystemUI/tests/AndroidManifest.xml
@@ -23,6 +23,8 @@
<uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" />
<uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
<uses-permission android:name="android.permission.MANAGE_USERS" />
+ <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
+ <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<application>
<uses-library android:name="android.test.runner" />
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/TouchAnimatorTests.java b/packages/SystemUI/tests/src/com/android/systemui/qs/TouchAnimatorTests.java
index 1d81fd4..e9b85b9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/TouchAnimatorTests.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/TouchAnimatorTests.java
@@ -14,11 +14,13 @@
package com.android.systemui.qs;
+import android.test.suitebuilder.annotation.SmallTest;
import android.view.View;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.qs.TouchAnimator.Listener;
import org.mockito.Mockito;
+@SmallTest
public class TouchAnimatorTests extends SysuiTestCase {
private Listener mTouchListener;
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 f86c6a4..6a81659 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
@@ -32,9 +32,11 @@
import android.service.quicksettings.IQSTileService;
import android.service.quicksettings.Tile;
import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
import android.util.ArraySet;
import android.util.Log;
+@SmallTest
public class TileLifecycleManagerTests extends AndroidTestCase {
public static final String TILE_UPDATE_BROADCAST = "com.android.systemui.tests.TILE_UPDATE";
public static final String EXTRA_CALLBACK = "callback";
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServiceManagerTests.java b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServiceManagerTests.java
index efdb50d..f24b541 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServiceManagerTests.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServiceManagerTests.java
@@ -19,10 +19,12 @@
import android.os.Handler;
import android.os.HandlerThread;
import android.service.quicksettings.TileService;
+import android.test.suitebuilder.annotation.SmallTest;
import com.android.systemui.SysuiTestCase;
import org.mockito.ArgumentCaptor;
import org.mockito.Mockito;
+@SmallTest
public class TileServiceManagerTests extends SysuiTestCase {
private TileServices mTileServices;
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 01514646b..94c98d6 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.test.suitebuilder.annotation.SmallTest;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.statusbar.phone.QSTileHost;
import com.android.systemui.statusbar.policy.DataSaverController;
@@ -27,6 +28,7 @@
import java.util.ArrayList;
+@SmallTest
public class TileServicesTests extends SysuiTestCase {
private static int NUM_FAKES = TileServices.DEFAULT_MAX_BOUND * 2;
diff --git a/packages/VpnDialogs/AndroidManifest.xml b/packages/VpnDialogs/AndroidManifest.xml
index 32e1e6d..08257b6 100644
--- a/packages/VpnDialogs/AndroidManifest.xml
+++ b/packages/VpnDialogs/AndroidManifest.xml
@@ -24,7 +24,7 @@
<application android:label="VpnDialogs"
android:allowBackup="false" >
<activity android:name=".ConfirmDialog"
- android:theme="@*android:style/Theme.Material.DayNight.Dialog.Alert">
+ android:theme="@android:style/Theme.Material.Light.Dialog.Alert">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.DEFAULT"/>
@@ -32,7 +32,7 @@
</activity>
<activity android:name=".ManageDialog"
- android:theme="@*android:style/Theme.Material.DayNight.Dialog.Alert"
+ android:theme="@android:style/Theme.Material.Light.Dialog.Alert"
android:noHistory="true">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
diff --git a/packages/WallpaperCropper/res/values/styles.xml b/packages/WallpaperCropper/res/values/styles.xml
index 0f9e247..6a56afd 100644
--- a/packages/WallpaperCropper/res/values/styles.xml
+++ b/packages/WallpaperCropper/res/values/styles.xml
@@ -15,7 +15,7 @@
-->
<resources>
- <style name="Theme.WallpaperCropper" parent="@*android:style/Theme.Material.DayNight">
+ <style name="Theme.WallpaperCropper" parent="@android:style/Theme.Material.Light">
<item name="android:actionBarStyle">@style/WallpaperCropperActionBar</item>
<item name="android:windowFullscreen">true</item>
<item name="android:windowActionBarOverlay">true</item>
diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto
index d6f1499..b3613df 100644
--- a/proto/src/metrics_constants.proto
+++ b/proto/src/metrics_constants.proto
@@ -2017,6 +2017,124 @@
// action pass package name of calling package.
ACTION_SCOPED_DIRECTORY_ACCESS_DENIED_AND_PERSIST_BY_PACKAGE = 356;
+ // Logged when a user dismisses all task in overview
+ OVERVIEW_DISMISS_ALL = 357;
+
+ // Quick Settings -> Edit
+ QS_EDIT = 358;
+
+ // Quick Settings -> Edit -> Overflow -> Reset
+ ACTION_QS_EDIT_RESET = 359;
+
+ // QS -> Edit - Drag a tile out of the active tiles.
+ // The _SPEC contains either the spec of the tile or
+ // the package of the 3rd party app in the PKG field.
+ ACTION_QS_EDIT_REMOVE_SPEC = 360;
+ ACTION_QS_EDIT_REMOVE = 361;
+
+ // QS -> Edit - Drag a tile into the active tiles.
+ // The _SPEC contains either the spec of the tile or
+ // the package of the 3rd party app in the PKG field.
+ ACTION_QS_EDIT_ADD_SPEC = 362;
+ ACTION_QS_EDIT_ADD = 363;
+
+ // QS -> Edit - Drag a tile within the active tiles.
+ // The _SPEC contains either the spec of the tile or
+ // the package of the 3rd party app in the PKG field.
+ ACTION_QS_EDIT_MOVE_SPEC = 364;
+ ACTION_QS_EDIT_MOVE = 365;
+
+ // Long-press on a QS tile. Tile spec in package field.
+ ACTION_QS_LONG_PRESS = 366;
+
+ // OPEN: SUW Welcome Screen -> Vision Settings
+ // CATEGORY: SETTINGS
+ // OS: N
+ SUW_ACCESSIBILITY = 367;
+
+ // OPEN: SUW Welcome Screen -> Vision Settings -> Magnification gesture
+ // ACTION: New magnification gesture configuration is chosen
+ // SUBTYPE: 0 is off, 1 is on
+ // CATEGORY: SETTINGS
+ // OS: N
+ SUW_ACCESSIBILITY_TOGGLE_SCREEN_MAGNIFICATION = 368;
+
+ // OPEN: SUW Welcome Screen -> Vision Settings -> Font size
+ // ACTION: New font size is chosen
+ // SUBTYPE: 0 is small, 1 is default, 2 is large, 3 is largest
+ // CATEGORY: SETTINGS
+ // OS: N
+ SUW_ACCESSIBILITY_FONT_SIZE = 369;
+
+ // OPEN: SUW Welcome Screen -> Vision Settings -> Display size
+ // ACTION: New display size is chosen
+ // SUBTYPE: 0 is small, 1 is default, 2 is large, 3 is larger, 4 is largest
+ // CATEGORY: SETTINGS
+ // OS: N
+ SUW_ACCESSIBILITY_DISPLAY_SIZE = 370;
+
+ // OPEN: SUW Welcome Screen -> Vision Settings -> TalkBack
+ // ACTION: New screen reader configuration is chosen
+ // SUBTYPE: 0 is off, 1 is on
+ // CATEGORY: SETTINGS
+ // OS: N
+ SUW_ACCESSIBILITY_TOGGLE_SCREEN_READER = 371;
+
+ // ------- Begin N Settings conditionals -----
+ // Conditionals are the green bars at the top of the settings dashboard
+ // All conditionals will have visible/hide events onResume/onPause
+ // but they will also be used as extra ints in the
+ // dismiss/expand/collapse/click/button events
+
+ // swipe away conditional
+ ACTION_SETTINGS_CONDITION_DISMISS = 372;
+
+ // click on collapsed conditional or clicks expand button
+ ACTION_SETTINGS_CONDITION_EXPAND = 373;
+
+ // click collapse button on expanded conditional
+ ACTION_SETTINGS_CONDITION_COLLAPSE = 374;
+
+ // click main area of expanded conditional
+ ACTION_SETTINGS_CONDITION_CLICK = 375;
+
+ // click a direct button on expanded conditional
+ ACTION_SETTINGS_CONDITION_BUTTON = 376;
+
+ // Airplane mode on
+ SETTINGS_CONDITION_AIRPLANE_MODE = 377;
+ // AKA Data saver on
+ SETTINGS_CONDITION_BACKGROUND_DATA = 378;
+ // Battery saver on
+ SETTINGS_CONDITION_BATTERY_SAVER = 379;
+ // Cellular data off
+ SETTINGS_CONDITION_CELLULAR_DATA = 380;
+ // Do not disturb on
+ SETTINGS_CONDITION_DND = 381;
+ // Hotspot on
+ SETTINGS_CONDITION_HOTSPOT = 382;
+ // Work profile off
+ SETTINGS_CONDITION_WORK_MODE = 383;
+
+ // ------- Begin N Settings suggestions -----
+ // Since suggestions come from system apps, suggestions will
+ // have generic constants and the package providing the suggestion
+ // will be put in the package field. For suggestions in the Settings
+ // package, the class name will be filled in instead (since settings
+ // provides several suggetions).
+
+ // Settings shown/hidden on main settings dashboard.
+ // These are actually visibility events, but visible/hidden doesn't
+ // take a package, so these are being logged as actions.
+ ACTION_SHOW_SETTINGS_SUGGESTION = 384;
+ ACTION_HIDE_SETTINGS_SUGGESTION = 385;
+
+ // Click on a suggestion.
+ ACTION_SETTINGS_SUGGESTION = 386;
+
+ // Suggestion -> Overflow -> Remove.
+ ACTION_SETTINGS_DISMISS_SUGGESTION = 387;
+
// Add new aosp constants above this line.
// END OF AOSP CONSTANTS
}
diff --git a/rs/java/android/renderscript/Allocation.java b/rs/java/android/renderscript/Allocation.java
index fc92966..9ec6e8d 100644
--- a/rs/java/android/renderscript/Allocation.java
+++ b/rs/java/android/renderscript/Allocation.java
@@ -142,7 +142,10 @@
}
return Element.DataType.FLOAT_64;
}
- return null;
+
+ throw new RSIllegalArgumentException("Parameter of type " + cmp.getSimpleName() +
+ "[] is not compatible with data type " + mType.mElement.mType.name() +
+ " of allocation");
}
@@ -293,8 +296,13 @@
}
/**
- * Enable/Disable AutoPadding for Vec3 elements.
- * By default: Diabled.
+ * Enable/Disable AutoPadding for Vec3 Elements.
+ *
+ * <p> Vec3 Elements, such as {@link Element#U8_3} are treated as Vec4 Elements
+ * with the fourth vector element used as padding. Enabling the AutoPadding feature
+ * will automatically add/remove the padding when you copy to/from an Allocation
+ * with a Vec3 Element.
+ * <p> By default: Disabled.
*
* @param useAutoPadding True: enable AutoPadding; False: disable AutoPadding
*
@@ -372,6 +380,7 @@
Log.e(RenderScript.LOG_TAG, "Couldn't invoke registerNativeAllocation:" + e);
throw new RSRuntimeException("Couldn't invoke registerNativeAllocation:" + e);
}
+ guard.open("destroy");
}
Allocation(long id, RenderScript rs, Type t, int usage, MipmapControl mips) {
@@ -1907,6 +1916,7 @@
if (type.getID(rs) == 0) {
throw new RSInvalidStateException("Bad Type");
}
+ // TODO: What if there is an exception after this? The native allocation would leak.
long id = rs.nAllocationCreateTyped(type.getID(rs), mips.mID, usage, 0);
if (id == 0) {
throw new RSRuntimeException("Allocation creation failed.");
diff --git a/rs/java/android/renderscript/BaseObj.java b/rs/java/android/renderscript/BaseObj.java
index 1372ab7..f95af16 100644
--- a/rs/java/android/renderscript/BaseObj.java
+++ b/rs/java/android/renderscript/BaseObj.java
@@ -16,6 +16,7 @@
package android.renderscript;
+import dalvik.system.CloseGuard;
import java.util.concurrent.locks.ReentrantReadWriteLock;
/**
@@ -69,6 +70,7 @@
}
private long mID;
+ final CloseGuard guard = CloseGuard.get();
private boolean mDestroyed;
private String mName;
RenderScript mRS;
@@ -119,6 +121,7 @@
}
if (shouldDestroy) {
+ guard.close();
// must include nObjDestroy in the critical section
ReentrantReadWriteLock.ReadLock rlock = mRS.mRWLock.readLock();
rlock.lock();
@@ -133,8 +136,14 @@
}
protected void finalize() throws Throwable {
- helpDestroy();
- super.finalize();
+ try {
+ if (guard != null) {
+ guard.warnIfOpen();
+ }
+ helpDestroy();
+ } finally {
+ super.finalize();
+ }
}
/**
diff --git a/rs/java/android/renderscript/Element.java b/rs/java/android/renderscript/Element.java
index 6efb6d6..50226ac 100644
--- a/rs/java/android/renderscript/Element.java
+++ b/rs/java/android/renderscript/Element.java
@@ -808,6 +808,7 @@
mSize += mElements[ct].mSize * mArraySizes[ct];
}
updateVisibleSubElements();
+ guard.open("destroy");
}
Element(long id, RenderScript rs, DataType dt, DataKind dk, boolean norm, int size) {
@@ -827,6 +828,7 @@
mKind = dk;
mNormalized = norm;
mVectorSize = size;
+ guard.open("destroy");
}
Element(long id, RenderScript rs) {
diff --git a/rs/java/android/renderscript/FileA3D.java b/rs/java/android/renderscript/FileA3D.java
index 9d8f162..278d309 100644
--- a/rs/java/android/renderscript/FileA3D.java
+++ b/rs/java/android/renderscript/FileA3D.java
@@ -170,6 +170,7 @@
FileA3D(long id, RenderScript rs, InputStream stream) {
super(id, rs);
mInputStream = stream;
+ guard.open("destroy");
}
private void initEntries() {
diff --git a/rs/java/android/renderscript/Font.java b/rs/java/android/renderscript/Font.java
index 4318b9d..d5ca31e 100644
--- a/rs/java/android/renderscript/Font.java
+++ b/rs/java/android/renderscript/Font.java
@@ -150,6 +150,7 @@
Font(long id, RenderScript rs) {
super(id, rs);
+ guard.open("destroy");
}
/**
diff --git a/rs/java/android/renderscript/Mesh.java b/rs/java/android/renderscript/Mesh.java
index 13c8e1c..9e4f905 100644
--- a/rs/java/android/renderscript/Mesh.java
+++ b/rs/java/android/renderscript/Mesh.java
@@ -91,6 +91,7 @@
Mesh(long id, RenderScript rs) {
super(id, rs);
+ guard.open("destroy");
}
/**
diff --git a/rs/java/android/renderscript/Program.java b/rs/java/android/renderscript/Program.java
index 3eb9b75..772021c 100644
--- a/rs/java/android/renderscript/Program.java
+++ b/rs/java/android/renderscript/Program.java
@@ -76,6 +76,7 @@
Program(long id, RenderScript rs) {
super(id, rs);
+ guard.open("destroy");
}
/**
diff --git a/rs/java/android/renderscript/RenderScript.java b/rs/java/android/renderscript/RenderScript.java
index 9beaba3..2650e5a 100644
--- a/rs/java/android/renderscript/RenderScript.java
+++ b/rs/java/android/renderscript/RenderScript.java
@@ -1031,7 +1031,6 @@
- long mDev;
long mContext;
private boolean mDestroyed = false;
@@ -1426,8 +1425,8 @@
RenderScript rs = new RenderScript(ctx);
- rs.mDev = rs.nDeviceCreate();
- rs.mContext = rs.nContextCreate(rs.mDev, flags, sdkVersion, ct.mID);
+ long device = rs.nDeviceCreate();
+ rs.mContext = rs.nContextCreate(device, flags, sdkVersion, ct.mID);
rs.mContextType = ct;
rs.mContextFlags = flags;
rs.mContextSdkVersion = sdkVersion;
@@ -1635,9 +1634,6 @@
}
nContextDestroy();
-
- nDeviceDestroy(mDev);
- mDev = 0;
}
}
diff --git a/rs/java/android/renderscript/RenderScriptGL.java b/rs/java/android/renderscript/RenderScriptGL.java
index 6178994..be1f899 100644
--- a/rs/java/android/renderscript/RenderScriptGL.java
+++ b/rs/java/android/renderscript/RenderScriptGL.java
@@ -177,9 +177,9 @@
mWidth = 0;
mHeight = 0;
- mDev = nDeviceCreate();
+ long device = nDeviceCreate();
int dpi = ctx.getResources().getDisplayMetrics().densityDpi;
- mContext = nContextCreateGL(mDev, 0, sdkVersion,
+ mContext = nContextCreateGL(device, 0, sdkVersion,
mSurfaceConfig.mColorMin, mSurfaceConfig.mColorPref,
mSurfaceConfig.mAlphaMin, mSurfaceConfig.mAlphaPref,
mSurfaceConfig.mDepthMin, mSurfaceConfig.mDepthPref,
diff --git a/rs/java/android/renderscript/Sampler.java b/rs/java/android/renderscript/Sampler.java
index a4edbb5..5c4bae9 100644
--- a/rs/java/android/renderscript/Sampler.java
+++ b/rs/java/android/renderscript/Sampler.java
@@ -51,6 +51,7 @@
Sampler(long id, RenderScript rs) {
super(id, rs);
+ guard.open("destroy");
}
/**
diff --git a/rs/java/android/renderscript/Script.java b/rs/java/android/renderscript/Script.java
index 2b06780..fc3280b 100644
--- a/rs/java/android/renderscript/Script.java
+++ b/rs/java/android/renderscript/Script.java
@@ -41,6 +41,7 @@
mScript = s;
mSlot = slot;
mSig = sig;
+ guard.open("destroy");
}
}
@@ -118,6 +119,7 @@
super(id, rs);
mScript = s;
mSlot = slot;
+ guard.open("destroy");
}
}
@@ -357,6 +359,19 @@
super(id, rs);
mInIdsBuffer = new long[1];
+
+ /* The constructors for the derived classes (including ScriptIntrinsic
+ * derived classes and ScriptC derived classes generated by Slang
+ * reflection) seem to be simple enough, so we just put the guard.open()
+ * call here, rather than in the end of the constructor for the derived
+ * class. This, of course, assumes the derived constructor would not
+ * throw any exception after calling this constructor.
+ *
+ * If new derived classes are added with more complicated constructors
+ * that throw exceptions, this call has to be (duplicated and) moved
+ * to the end of each derived class constructor.
+ */
+ guard.open("destroy");
}
/**
@@ -541,21 +556,22 @@
/**
* Class for specifying the specifics about how a kernel will be
- * launched
+ * launched.
*
* This class can specify a potential range of cells on which to
* run a kernel. If no set is called for a dimension then this
* class will have no impact on that dimension when the kernel
* is executed.
*
- * The forEach launch will operate over the intersection of the
- * dimensions.
+ * The forEach kernel launch will operate over the intersection of
+ * the dimensions.
*
* Example:
* LaunchOptions with setX(5, 15)
* Allocation with dimension X=10, Y=10
- * The resulting forEach run would execute over x = 5 to 10 and
- * y = 0 to 10.
+ * The resulting forEach run would execute over:
+ * x = 5 to 9 (inclusive) and
+ * y = 0 to 9 (inclusive).
*
*
*/
@@ -569,11 +585,11 @@
private int strategy;
/**
- * Set the X range. If the end value is set to 0 the X dimension is not
- * clipped.
+ * Set the X range. xstartArg is the lowest coordinate of the range,
+ * and xendArg-1 is the highest coordinate of the range.
*
* @param xstartArg Must be >= 0
- * @param xendArg Must be >= xstartArg
+ * @param xendArg Must be > xstartArg
*
* @return LaunchOptions
*/
@@ -587,11 +603,11 @@
}
/**
- * Set the Y range. If the end value is set to 0 the Y dimension is not
- * clipped.
+ * Set the Y range. ystartArg is the lowest coordinate of the range,
+ * and yendArg-1 is the highest coordinate of the range.
*
* @param ystartArg Must be >= 0
- * @param yendArg Must be >= ystartArg
+ * @param yendArg Must be > ystartArg
*
* @return LaunchOptions
*/
@@ -605,11 +621,11 @@
}
/**
- * Set the Z range. If the end value is set to 0 the Z dimension is not
- * clipped.
+ * Set the Z range. zstartArg is the lowest coordinate of the range,
+ * and zendArg-1 is the highest coordinate of the range.
*
* @param zstartArg Must be >= 0
- * @param zendArg Must be >= zstartArg
+ * @param zendArg Must be > zstartArg
*
* @return LaunchOptions
*/
diff --git a/rs/java/android/renderscript/ScriptGroup.java b/rs/java/android/renderscript/ScriptGroup.java
index 9357c3bb..219f16b 100644
--- a/rs/java/android/renderscript/ScriptGroup.java
+++ b/rs/java/android/renderscript/ScriptGroup.java
@@ -148,6 +148,8 @@
fieldIDs, values, sizes, depClosures, depFieldIDs);
setID(id);
+
+ guard.open("destroy");
}
Closure(RenderScript rs, Script.InvokeID invokeID,
@@ -181,6 +183,8 @@
values, sizes);
setID(id);
+
+ guard.open("destroy");
}
private void retrieveValueAndDependenceInfo(RenderScript rs,
@@ -382,6 +386,7 @@
ScriptGroup(long id, RenderScript rs) {
super(id, rs);
+ guard.open("destroy");
}
ScriptGroup(RenderScript rs, String name, List<Closure> closures,
@@ -398,6 +403,7 @@
}
long id = rs.nScriptGroup2Create(name, RenderScript.getCachePath(), closureIDs);
setID(id);
+ guard.open("destroy");
}
/**
diff --git a/rs/java/android/renderscript/ScriptIntrinsicConvolve3x3.java b/rs/java/android/renderscript/ScriptIntrinsicConvolve3x3.java
index 76da781..339e0e9 100644
--- a/rs/java/android/renderscript/ScriptIntrinsicConvolve3x3.java
+++ b/rs/java/android/renderscript/ScriptIntrinsicConvolve3x3.java
@@ -32,10 +32,9 @@
* Supported elements types are {@link Element#U8}, {@link
* Element#U8_2}, {@link Element#U8_3}, {@link Element#U8_4},
* {@link Element#F32}, {@link Element#F32_2}, {@link
- * Element#F32_3}, and {@link Element#F32_4}
+ * Element#F32_3}, and {@link Element#F32_4}.
*
- * The default coefficients are.
- *
+ * <p> The default coefficients are:
* <code>
* <p> [ 0, 0, 0 ]
* <p> [ 0, 1, 0 ]
@@ -67,7 +66,7 @@
}
/**
- * Set the input of the blur.
+ * Set the input of the 3x3 convolve.
* Must match the element type supplied during create.
*
* @param ain The input allocation.
@@ -80,7 +79,7 @@
/**
* Set the coefficients for the convolve.
*
- * The convolve layout is
+ * <p> The convolve layout is:
* <code>
* <p> [ 0, 1, 2 ]
* <p> [ 3, 4, 5 ]
diff --git a/rs/java/android/renderscript/ScriptIntrinsicConvolve5x5.java b/rs/java/android/renderscript/ScriptIntrinsicConvolve5x5.java
index 2d37600..a288cee 100644
--- a/rs/java/android/renderscript/ScriptIntrinsicConvolve5x5.java
+++ b/rs/java/android/renderscript/ScriptIntrinsicConvolve5x5.java
@@ -32,9 +32,9 @@
* Supported elements types are {@link Element#U8}, {@link
* Element#U8_2}, {@link Element#U8_3}, {@link Element#U8_4},
* {@link Element#F32}, {@link Element#F32_2}, {@link
- * Element#F32_3}, and {@link Element#F32_4}
+ * Element#F32_3}, and {@link Element#F32_4}.
*
- * The default coefficients are.
+ * <p> The default coefficients are:
* <code>
* <p> [ 0, 0, 0, 0, 0 ]
* <p> [ 0, 0, 0, 0, 0 ]
@@ -66,7 +66,7 @@
}
/**
- * Set the input of the blur.
+ * Set the input of the 5x5 convolve.
* Must match the element type supplied during create.
*
* @param ain The input allocation.
@@ -79,7 +79,7 @@
/**
* Set the coefficients for the convolve.
*
- * The convolve layout is
+ * <p> The convolve layout is:
* <code>
* <p> [ 0, 1, 2, 3, 4 ]
* <p> [ 5, 6, 7, 8, 9 ]
diff --git a/rs/java/android/renderscript/Type.java b/rs/java/android/renderscript/Type.java
index dc23785..9252898 100644
--- a/rs/java/android/renderscript/Type.java
+++ b/rs/java/android/renderscript/Type.java
@@ -227,6 +227,7 @@
Type(long id, RenderScript rs) {
super(id, rs);
+ guard.open("destroy");
}
@Override
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index e3dac28..e256ecd 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -1262,7 +1262,7 @@
Service service = componentNameToServiceMap.get(componentName);
// Ignore non-encryption-aware services until user is unlocked
- if (!isUnlocked && !installedService.isEncryptionAware()) {
+ if (!isUnlocked && !installedService.isDirectBootAware()) {
Slog.d(LOG_TAG, "Ignoring non-encryption-aware service " + componentName);
continue;
}
@@ -1774,17 +1774,27 @@
private void updateSoftKeyboardShowModeLocked(UserState userState) {
final int userId = userState.mUserId;
- if (userId == mCurrentUserId) {
- // Check whether any Accessibility Services are still enabled and, if not, remove flag
- // requesting no soft keyboard
- final boolean accessibilityRequestingNoIme = userState.mSoftKeyboardShowMode == 1;
- if (accessibilityRequestingNoIme && !userState.isHandlingAccessibilityEvents()) {
- // No active Accessibility Services can be requesting the soft keyboard to be hidden
- Settings.Secure.putIntForUser(mContext.getContentResolver(),
- Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE,
- 0,
- userState.mUserId);
+ // Only check whether we need to reset the soft keyboard mode if it is not set to the
+ // default.
+ if ((userId == mCurrentUserId) && (userState.mSoftKeyboardShowMode != 0)) {
+ // Check whether the last Accessibility Service that changed the soft keyboard mode to
+ // something other than the default is still enabled and, if not, remove flag and
+ // reset to the default soft keyboard behavior.
+ boolean serviceChangingSoftKeyboardModeIsEnabled =
+ userState.mEnabledServices.contains(userState.mServiceChangingSoftKeyboardMode);
+
+ if (!serviceChangingSoftKeyboardModeIsEnabled) {
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ Settings.Secure.putIntForUser(mContext.getContentResolver(),
+ Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE,
+ 0,
+ userState.mUserId);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
userState.mSoftKeyboardShowMode = 0;
+ userState.mServiceChangingSoftKeyboardMode = null;
}
notifySoftKeyboardShowModeChangedLocked(userState.mSoftKeyboardShowMode);
@@ -2966,6 +2976,14 @@
final long identity = Binder.clearCallingIdentity();
try {
+ // Keep track of the last service to request a non-default show mode. The show mode
+ // should be restored to default should this service be disabled.
+ if (showMode == Settings.Secure.SHOW_MODE_AUTO) {
+ userState.mServiceChangingSoftKeyboardMode = null;
+ } else {
+ userState.mServiceChangingSoftKeyboardMode = mComponentName;
+ }
+
Settings.Secure.putIntForUser(mContext.getContentResolver(),
Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE, showMode,
userState.mUserId);
@@ -3478,6 +3496,8 @@
reportedWindow.setLayer(window.layer);
reportedWindow.setFocused(window.focused);
reportedWindow.setBoundsInScreen(window.boundsInScreen);
+ reportedWindow.setTitle(window.title);
+ reportedWindow.setAnchorId(window.accessibilityIdOfAnchor);
final int parentId = findWindowIdLocked(window.parentToken);
if (parentId >= 0) {
@@ -4115,6 +4135,8 @@
public final Set<ComponentName> mTouchExplorationGrantedServices =
new HashSet<>();
+ public ComponentName mServiceChangingSoftKeyboardMode;
+
public int mLastSentClientState = -1;
public int mSoftKeyboardShowMode = 0;
diff --git a/services/accessibility/java/com/android/server/accessibility/MagnificationController.java b/services/accessibility/java/com/android/server/accessibility/MagnificationController.java
index a093d92..e15b785 100644
--- a/services/accessibility/java/com/android/server/accessibility/MagnificationController.java
+++ b/services/accessibility/java/com/android/server/accessibility/MagnificationController.java
@@ -111,12 +111,18 @@
public void register() {
mScreenStateObserver.register();
mWindowStateObserver.register();
+
+ // Obtain initial state.
+ mWindowStateObserver.getRegions(mMagnifiedRegion, mAvailableRegion);
+ mMagnifiedRegion.getBounds(mMagnifiedBounds);
}
/**
* Unregisters magnification-related observers.
*/
public void unregister() {
+ mSpecAnimationBridge.cancel();
+
mScreenStateObserver.unregister();
mWindowStateObserver.unregister();
}
@@ -149,8 +155,10 @@
final float offsetY = sentSpec.offsetY;
// Compute the new center and update spec as needed.
- final float centerX = (mMagnifiedBounds.width() / 2.0f - offsetX) / scale;
- final float centerY = (mMagnifiedBounds.height() / 2.0f - offsetY) / scale;
+ final float centerX = (mMagnifiedBounds.width() / 2.0f
+ + mMagnifiedBounds.left - offsetX) / scale;
+ final float centerY = (mMagnifiedBounds.height() / 2.0f
+ + mMagnifiedBounds.top - offsetY) / scale;
if (updateSpec) {
setScaleAndCenter(scale, centerX, centerY, false);
} else {
@@ -246,7 +254,8 @@
*/
public float getCenterX() {
synchronized (mLock) {
- return (mMagnifiedBounds.width() / 2.0f - getOffsetX()) / getScale();
+ return (mMagnifiedBounds.width() / 2.0f
+ + mMagnifiedBounds.left - getOffsetX()) / getScale();
}
}
@@ -268,7 +277,8 @@
*/
public float getCenterY() {
synchronized (mLock) {
- return (mMagnifiedBounds.height() / 2.0f - getOffsetY()) / getScale();
+ return (mMagnifiedBounds.height() / 2.0f
+ + mMagnifiedBounds.top - getOffsetY()) / getScale();
}
}
@@ -471,18 +481,25 @@
* otherwise
*/
private boolean updateMagnificationSpecLocked(float scale, float centerX, float centerY) {
+ // Handle defaults.
+ if (Float.isNaN(centerX)) {
+ centerX = getCenterX();
+ }
+ if (Float.isNaN(centerY)) {
+ centerY = getCenterY();
+ }
+ if (Float.isNaN(scale)) {
+ scale = getScale();
+ }
+
+ // Ensure requested center is within the available region.
if (!availableRegionContains(centerX, centerY)) {
return false;
}
- boolean changed = false;
-
+ // Compute changes.
final MagnificationSpec currSpec = mCurrentMagnificationSpec;
-
- // Handle scale.
- if (Float.isNaN(scale)) {
- scale = getScale();
- }
+ boolean changed = false;
final float normScale = MathUtils.constrain(scale, MIN_SCALE, MAX_SCALE);
if (Float.compare(currSpec.scale, normScale) != 0) {
@@ -490,24 +507,16 @@
changed = true;
}
- // Handle X offset.
- if (Float.isNaN(centerX)) {
- centerX = getCenterX();
- }
-
- final float nonNormOffsetX = mMagnifiedBounds.width() / 2.0f - centerX * scale;
+ final float nonNormOffsetX = mMagnifiedBounds.width() / 2.0f
+ + mMagnifiedBounds.left - centerX * scale;
final float offsetX = MathUtils.constrain(nonNormOffsetX, getMinOffsetXLocked(), 0);
if (Float.compare(currSpec.offsetX, offsetX) != 0) {
currSpec.offsetX = offsetX;
changed = true;
}
- // Handle Y offset.
- if (Float.isNaN(centerY)) {
- centerY = getCenterY();
- }
-
- final float nonNormOffsetY = mMagnifiedBounds.height() / 2.0f - centerY * scale;
+ final float nonNormOffsetY = mMagnifiedBounds.height() / 2.0f
+ + mMagnifiedBounds.top - centerY * scale;
final float offsetY = MathUtils.constrain(nonNormOffsetY, getMinOffsetYLocked(), 0);
if (Float.compare(currSpec.offsetY, offsetY) != 0) {
currSpec.offsetY = offsetY;
@@ -661,6 +670,12 @@
mTransformationAnimator.setInterpolator(new DecelerateInterpolator(2.5f));
}
+ public void cancel() {
+ if (mTransformationAnimator != null && mTransformationAnimator.isRunning()) {
+ mTransformationAnimator.cancel();
+ }
+ }
+
public void updateSentSpec(MagnificationSpec spec, boolean animate) {
if (Thread.currentThread().getId() == mMainThreadId) {
// Already on the main thread, don't bother proxying.
@@ -811,9 +826,6 @@
private static final int MESSAGE_ON_USER_CONTEXT_CHANGED = 3;
private static final int MESSAGE_ON_ROTATION_CHANGED = 4;
- private final Rect mTempRect = new Rect();
- private final Rect mTempRect1 = new Rect();
-
private final MagnificationController mController;
private final WindowManagerInternal mWindowManager;
private final Handler mHandler;
@@ -884,6 +896,10 @@
mController.resetIfNeeded(true);
}
+ public void getRegions(@NonNull Region outMagnified, @NonNull Region outAvailable) {
+ mWindowManager.getMagnificationRegions(outMagnified, outAvailable);
+ }
+
private class CallbackHandler extends Handler {
public CallbackHandler(Context context) {
super(context.getMainLooper());
diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
index 215be4a..b6a99c8 100644
--- a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
+++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
@@ -164,7 +164,8 @@
onUserStopped(userId);
} else if (Intent.ACTION_USER_SWITCHED.equals(action)) {
reloadWidgetsMaskedStateForGroup(userId);
- } else if (Intent.ACTION_MANAGED_PROFILE_AVAILABILITY_CHANGED.equals(action)) {
+ } else if (Intent.ACTION_MANAGED_PROFILE_AVAILABLE.equals(action)
+ || Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE.equals(action)) {
synchronized (mLock) {
reloadWidgetsMaskedState(userId);
}
@@ -288,7 +289,8 @@
userFilter, null, null);
IntentFilter offModeFilter = new IntentFilter();
- offModeFilter.addAction(Intent.ACTION_MANAGED_PROFILE_AVAILABILITY_CHANGED);
+ offModeFilter.addAction(Intent.ACTION_MANAGED_PROFILE_AVAILABLE);
+ offModeFilter.addAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE);
mContext.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL,
offModeFilter, null, null);
@@ -486,8 +488,14 @@
boolean changed = provider.setMaskedByLockedProfileLocked(lockedProfile);
changed |= provider.setMaskedByQuietProfileLocked(quietProfile);
try {
- boolean suspended = mPackageManager.isPackageSuspendedForUser(
- provider.info.provider.getPackageName(), provider.getUserId());
+ boolean suspended;
+ try {
+ suspended = mPackageManager.isPackageSuspendedForUser(
+ provider.info.provider.getPackageName(), provider.getUserId());
+ } catch (IllegalArgumentException ex) {
+ // Package not found.
+ suspended = false;
+ }
changed |= provider.setMaskedBySuspendedPackageLocked(suspended);
} catch (RemoteException e) {
Slog.e(TAG, "Failed to query application info", e);
diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java
index b737ae2..6288b56 100644
--- a/services/backup/java/com/android/server/backup/BackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/BackupManagerService.java
@@ -1818,7 +1818,7 @@
File initSentinel = new File(stateDir, INIT_SENTINEL_FILE_NAME);
if (initSentinel.exists()) {
synchronized (mQueueLock) {
- mPendingInits.add(transportName);
+ mPendingInits.add(name);
// TODO: pick a better starting time than now + 1 minute
long delay = 1000 * 60; // one minute, in milliseconds
@@ -2316,6 +2316,25 @@
}
}
+ // What name is this transport registered under...?
+ private String getTransportName(IBackupTransport transport) {
+ if (MORE_DEBUG) {
+ Slog.v(TAG, "Searching for transport name of " + transport);
+ }
+ synchronized (mTransports) {
+ final int N = mTransports.size();
+ for (int i = 0; i < N; i++) {
+ if (mTransports.valueAt(i).equals(transport)) {
+ if (MORE_DEBUG) {
+ Slog.v(TAG, " Name found: " + mTransports.keyAt(i));
+ }
+ return mTransports.keyAt(i);
+ }
+ }
+ }
+ return null;
+ }
+
// fire off a backup agent, blocking until it attaches or times out
IBackupAgent bindToAgentSynchronous(ApplicationInfo app, int mode) {
IBackupAgent agent = null;
@@ -2921,7 +2940,15 @@
if (MORE_DEBUG) Slog.d(TAG, "Server requires init; rerunning");
addBackupTrace("init required; rerunning");
try {
- mPendingInits.add(mTransport.transportDirName());
+ final String name = getTransportName(mTransport);
+ if (name != null) {
+ mPendingInits.add(name);
+ } else {
+ if (DEBUG) {
+ Slog.w(TAG, "Couldn't find name of transport " + mTransport
+ + " for init");
+ }
+ }
} catch (Exception e) {
Slog.w(TAG, "Failed to query transport name heading for init", e);
// swallow it and proceed; we don't rely on this
@@ -7590,77 +7617,6 @@
// ----- Restore handling -----
- // new style: we only store the SHA-1 hashes of each sig, not the full block
- static boolean signaturesMatch(ArrayList<byte[]> storedSigHashes, PackageInfo target) {
- if (target == null) {
- return false;
- }
-
- // If the target resides on the system partition, we allow it to restore
- // data from the like-named package in a restore set even if the signatures
- // do not match. (Unlike general applications, those flashed to the system
- // partition will be signed with the device's platform certificate, so on
- // different phones the same system app will have different signatures.)
- if ((target.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
- if (MORE_DEBUG) Slog.v(TAG, "System app " + target.packageName + " - skipping sig check");
- return true;
- }
-
- // Allow unsigned apps, but not signed on one device and unsigned on the other
- // !!! TODO: is this the right policy?
- Signature[] deviceSigs = target.signatures;
- if (MORE_DEBUG) Slog.v(TAG, "signaturesMatch(): stored=" + storedSigHashes
- + " device=" + deviceSigs);
- if ((storedSigHashes == null || storedSigHashes.size() == 0)
- && (deviceSigs == null || deviceSigs.length == 0)) {
- return true;
- }
- if (storedSigHashes == null || deviceSigs == null) {
- return false;
- }
-
- // !!! TODO: this demands that every stored signature match one
- // that is present on device, and does not demand the converse.
- // Is this this right policy?
- final int nStored = storedSigHashes.size();
- final int nDevice = deviceSigs.length;
-
- // hash each on-device signature
- ArrayList<byte[]> deviceHashes = new ArrayList<byte[]>(nDevice);
- for (int i = 0; i < nDevice; i++) {
- deviceHashes.add(hashSignature(deviceSigs[i]));
- }
-
- // now ensure that each stored sig (hash) matches an on-device sig (hash)
- for (int n = 0; n < nStored; n++) {
- boolean match = false;
- final byte[] storedHash = storedSigHashes.get(n);
- for (int i = 0; i < nDevice; i++) {
- if (Arrays.equals(storedHash, deviceHashes.get(i))) {
- match = true;
- break;
- }
- }
- // match is false when no on-device sig matched one of the stored ones
- if (!match) {
- return false;
- }
- }
-
- return true;
- }
-
- static byte[] hashSignature(Signature sig) {
- try {
- MessageDigest digest = MessageDigest.getInstance("SHA-256");
- digest.update(sig.toByteArray());
- return digest.digest();
- } catch (NoSuchAlgorithmException e) {
- Slog.w(TAG, "No SHA-256 algorithm found!");
- }
- return null;
- }
-
// Old style: directly match the stored vs on device signature blocks
static boolean signaturesMatch(Signature[] storedSigs, PackageInfo target) {
if (target == null) {
@@ -8173,7 +8129,7 @@
}
Metadata metaInfo = mPmAgent.getRestoredMetadata(packageName);
- if (!signaturesMatch(metaInfo.sigHashes, mCurrentPackage)) {
+ if (!BackupUtils.signaturesMatch(metaInfo.sigHashes, mCurrentPackage)) {
Slog.w(TAG, "Signature mismatch restoring " + packageName);
EventLog.writeEvent(EventLogTags.RESTORE_AGENT_FAILURE, packageName,
"Signature mismatch");
diff --git a/services/backup/java/com/android/server/backup/PackageManagerBackupAgent.java b/services/backup/java/com/android/server/backup/PackageManagerBackupAgent.java
index f197c1e..09f240f 100644
--- a/services/backup/java/com/android/server/backup/PackageManagerBackupAgent.java
+++ b/services/backup/java/com/android/server/backup/PackageManagerBackupAgent.java
@@ -205,7 +205,7 @@
PackageManager.GET_SIGNATURES);
homeInstaller = mPackageManager.getInstallerPackageName(home.getPackageName());
homeVersion = homeInfo.versionCode;
- homeSigHashes = hashSignatureArray(homeInfo.signatures);
+ homeSigHashes = BackupUtils.hashSignatureArray(homeInfo.signatures);
} catch (NameNotFoundException e) {
Slog.w(TAG, "Can't access preferred home info");
// proceed as though there were no preferred home set
@@ -222,7 +222,7 @@
final boolean needHomeBackup = (homeVersion != mStoredHomeVersion)
|| !Objects.equals(home, mStoredHomeComponent)
|| (home != null
- && !BackupManagerService.signaturesMatch(mStoredHomeSigHashes, homeInfo));
+ && !BackupUtils.signaturesMatch(mStoredHomeSigHashes, homeInfo));
if (needHomeBackup) {
if (DEBUG) {
Slog.i(TAG, "Home preference changed; backing up new state " + home);
@@ -309,7 +309,7 @@
outputBuffer.reset();
outputBufferStream.writeInt(info.versionCode);
writeSignatureHashArray(outputBufferStream,
- hashSignatureArray(info.signatures));
+ BackupUtils.hashSignatureArray(info.signatures));
if (DEBUG) {
Slog.v(TAG, "+ writing metadata for " + packName
@@ -432,18 +432,6 @@
mRestoredSignatures = sigMap;
}
- private static ArrayList<byte[]> hashSignatureArray(Signature[] sigs) {
- if (sigs == null) {
- return null;
- }
-
- ArrayList<byte[]> hashes = new ArrayList<byte[]>(sigs.length);
- for (Signature s : sigs) {
- hashes.add(BackupManagerService.hashSignature(s));
- }
- return hashes;
- }
-
private static void writeSignatureHashArray(DataOutputStream out, ArrayList<byte[]> hashes)
throws IOException {
// the number of entries in the array
@@ -492,13 +480,8 @@
}
if (nonHashFound) {
- ArrayList<byte[]> hashes =
- new ArrayList<byte[]>(sigs.size());
- for (int i = 0; i < sigs.size(); i++) {
- Signature s = new Signature(sigs.get(i));
- hashes.add(BackupManagerService.hashSignature(s));
- }
- sigs = hashes;
+ // Replace with the hashes.
+ sigs = BackupUtils.hashSignatureArray(sigs);
}
return sigs;
diff --git a/services/core/java/com/android/server/AppOpsService.java b/services/core/java/com/android/server/AppOpsService.java
index e7db2a8..c38a89e 100644
--- a/services/core/java/com/android/server/AppOpsService.java
+++ b/services/core/java/com/android/server/AppOpsService.java
@@ -25,7 +25,6 @@
import java.io.PrintWriter;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
@@ -447,8 +446,12 @@
int[] ops) {
mContext.enforcePermission(android.Manifest.permission.GET_APP_OPS_STATS,
Binder.getCallingPid(), Binder.getCallingUid(), null);
+ String resolvedPackageName = resolvePackageName(uid, packageName);
+ if (resolvedPackageName == null) {
+ return Collections.emptyList();
+ }
synchronized (this) {
- Ops pkgOps = getOpsLocked(uid, packageName, false);
+ Ops pkgOps = getOpsRawLocked(uid, resolvedPackageName, false);
if (pkgOps == null) {
return null;
}
@@ -466,7 +469,7 @@
private void pruneOp(Op op, int uid, String packageName) {
if (op.time == 0 && op.rejectTime == 0) {
- Ops ops = getOpsLocked(uid, packageName, false);
+ Ops ops = getOpsRawLocked(uid, packageName, false);
if (ops != null) {
ops.remove(op.op);
if (ops.size() <= 0) {
@@ -880,8 +883,12 @@
public int checkOperation(int code, int uid, String packageName) {
verifyIncomingUid(uid);
verifyIncomingOp(code);
+ String resolvedPackageName = resolvePackageName(uid, packageName);
+ if (resolvedPackageName == null) {
+ return AppOpsManager.MODE_IGNORED;
+ }
synchronized (this) {
- if (isOpRestricted(uid, code, packageName)) {
+ if (isOpRestricted(uid, code, resolvedPackageName)) {
return AppOpsManager.MODE_IGNORED;
}
code = AppOpsManager.opToSwitch(code);
@@ -892,7 +899,7 @@
return uidMode;
}
}
- Op op = getOpLocked(code, uid, packageName, false);
+ Op op = getOpLocked(code, uid, resolvedPackageName, false);
if (op == null) {
return AppOpsManager.opToDefaultMode(code);
}
@@ -902,7 +909,15 @@
@Override
public int checkAudioOperation(int code, int usage, int uid, String packageName) {
- if (isPackageSuspendedForUser(packageName, uid)) {
+ boolean suspended;
+ try {
+ suspended = isPackageSuspendedForUser(packageName, uid);
+ } catch (IllegalArgumentException ex) {
+ // Package not found.
+ suspended = false;
+ }
+
+ if (suspended) {
Log.i(TAG, "Audio disabled for suspended package=" + packageName + " for uid=" + uid);
return AppOpsManager.MODE_IGNORED;
}
@@ -968,6 +983,7 @@
@Override
public int checkPackage(int uid, String packageName) {
+ Preconditions.checkNotNull(packageName);
synchronized (this) {
if (getOpsRawLocked(uid, packageName, true) != null) {
return AppOpsManager.MODE_ALLOWED;
@@ -981,26 +997,39 @@
public int noteProxyOperation(int code, String proxyPackageName,
int proxiedUid, String proxiedPackageName) {
verifyIncomingOp(code);
- final int proxyMode = noteOperationUnchecked(code, Binder.getCallingUid(),
- proxyPackageName, -1, null);
+ final int proxyUid = Binder.getCallingUid();
+ String resolveProxyPackageName = resolvePackageName(proxyUid, proxyPackageName);
+ if (resolveProxyPackageName == null) {
+ return AppOpsManager.MODE_IGNORED;
+ }
+ final int proxyMode = noteOperationUnchecked(code, proxyUid,
+ resolveProxyPackageName, -1, null);
if (proxyMode != AppOpsManager.MODE_ALLOWED || Binder.getCallingUid() == proxiedUid) {
return proxyMode;
}
- return noteOperationUnchecked(code, proxiedUid, proxiedPackageName,
- Binder.getCallingUid(), proxyPackageName);
+ String resolveProxiedPackageName = resolvePackageName(proxiedUid, proxiedPackageName);
+ if (resolveProxiedPackageName == null) {
+ return AppOpsManager.MODE_IGNORED;
+ }
+ return noteOperationUnchecked(code, proxiedUid, resolveProxiedPackageName,
+ proxyMode, resolveProxyPackageName);
}
@Override
public int noteOperation(int code, int uid, String packageName) {
verifyIncomingUid(uid);
verifyIncomingOp(code);
- return noteOperationUnchecked(code, uid, packageName, 0, null);
+ String resolvedPackageName = resolvePackageName(uid, packageName);
+ if (resolvedPackageName == null) {
+ return AppOpsManager.MODE_IGNORED;
+ }
+ return noteOperationUnchecked(code, uid, resolvedPackageName, 0, null);
}
private int noteOperationUnchecked(int code, int uid, String packageName,
int proxyUid, String proxyPackageName) {
synchronized (this) {
- Ops ops = getOpsLocked(uid, packageName, true);
+ Ops ops = getOpsRawLocked(uid, packageName, true);
if (ops == null) {
if (DEBUG) Log.d(TAG, "noteOperation: no op for code " + code + " uid " + uid
+ " package " + packageName);
@@ -1048,16 +1077,20 @@
public int startOperation(IBinder token, int code, int uid, String packageName) {
verifyIncomingUid(uid);
verifyIncomingOp(code);
+ String resolvedPackageName = resolvePackageName(uid, packageName);
+ if (resolvedPackageName == null) {
+ return AppOpsManager.MODE_IGNORED;
+ }
ClientState client = (ClientState)token;
synchronized (this) {
- Ops ops = getOpsLocked(uid, packageName, true);
+ Ops ops = getOpsRawLocked(uid, resolvedPackageName, true);
if (ops == null) {
if (DEBUG) Log.d(TAG, "startOperation: no op for code " + code + " uid " + uid
- + " package " + packageName);
+ + " package " + resolvedPackageName);
return AppOpsManager.MODE_ERRORED;
}
Op op = getOpLocked(ops, code, true);
- if (isOpRestricted(uid, code, packageName)) {
+ if (isOpRestricted(uid, code, resolvedPackageName)) {
return AppOpsManager.MODE_IGNORED;
}
final int switchCode = AppOpsManager.opToSwitch(code);
@@ -1067,7 +1100,7 @@
if (uidMode != AppOpsManager.MODE_ALLOWED) {
if (DEBUG) Log.d(TAG, "noteOperation: reject #" + op.mode + " for code "
+ switchCode + " (" + code + ") uid " + uid + " package "
- + packageName);
+ + resolvedPackageName);
op.rejectTime = System.currentTimeMillis();
return uidMode;
}
@@ -1075,12 +1108,13 @@
final Op switchOp = switchCode != code ? getOpLocked(ops, switchCode, true) : op;
if (switchOp.mode != AppOpsManager.MODE_ALLOWED) {
if (DEBUG) Log.d(TAG, "startOperation: reject #" + op.mode + " for code "
- + switchCode + " (" + code + ") uid " + uid + " package " + packageName);
+ + switchCode + " (" + code + ") uid " + uid + " package "
+ + resolvedPackageName);
op.rejectTime = System.currentTimeMillis();
return switchOp.mode;
}
if (DEBUG) Log.d(TAG, "startOperation: allowing code " + code + " uid " + uid
- + " package " + packageName);
+ + " package " + resolvedPackageName);
if (op.nesting == 0) {
op.time = System.currentTimeMillis();
op.rejectTime = 0;
@@ -1098,9 +1132,16 @@
public void finishOperation(IBinder token, int code, int uid, String packageName) {
verifyIncomingUid(uid);
verifyIncomingOp(code);
- ClientState client = (ClientState)token;
+ String resolvedPackageName = resolvePackageName(uid, packageName);
+ if (resolvedPackageName == null) {
+ return;
+ }
+ if (!(token instanceof ClientState)) {
+ return;
+ }
+ ClientState client = (ClientState) token;
synchronized (this) {
- Op op = getOpLocked(code, uid, packageName, true);
+ Op op = getOpLocked(code, uid, resolvedPackageName, true);
if (op == null) {
return;
}
@@ -1116,6 +1157,9 @@
@Override
public int permissionToOpCode(String permission) {
+ if (permission == null) {
+ return AppOpsManager.OP_NONE;
+ }
return AppOpsManager.permissionToOpCode(permission);
}
@@ -1165,15 +1209,6 @@
return uidState;
}
- private Ops getOpsLocked(int uid, String packageName, boolean edit) {
- if (uid == 0) {
- packageName = "root";
- } else if (uid == Process.SHELL_UID) {
- packageName = "com.android.shell";
- }
- return getOpsRawLocked(uid, packageName, edit);
- }
-
private Ops getOpsRawLocked(int uid, String packageName, boolean edit) {
UidState uidState = getUidStateLocked(uid, edit);
if (uidState == null) {
@@ -1259,7 +1294,7 @@
}
private Op getOpLocked(int code, int uid, String packageName, boolean edit) {
- Ops ops = getOpsLocked(uid, packageName, edit);
+ Ops ops = getOpsRawLocked(uid, packageName, edit);
if (ops == null) {
return null;
}
@@ -1317,7 +1352,7 @@
if (AppOpsManager.opAllowSystemBypassRestriction(code)) {
// If we are the system, bypass user restrictions for certain codes
synchronized (this) {
- Ops ops = getOpsLocked(uid, packageName, true);
+ Ops ops = getOpsRawLocked(uid, packageName, true);
if ((ops != null) && ops.isPrivileged) {
return false;
}
@@ -1582,7 +1617,7 @@
out.startTag(null, "uid");
out.attribute(null, "n", Integer.toString(pkg.getUid()));
synchronized (this) {
- Ops ops = getOpsLocked(pkg.getUid(), pkg.getPackageName(), false);
+ Ops ops = getOpsRawLocked(pkg.getUid(), pkg.getPackageName(), false);
// Should always be present as the list of PackageOps is generated
// from Ops.
if (ops != null) {
@@ -1645,7 +1680,9 @@
int userId = UserHandle.USER_SYSTEM;
String packageName;
String opStr;
+ String modeStr;
int op;
+ int mode;
int packageUid;
Shell(IAppOpsService iface, AppOpsService internal) {
@@ -1681,6 +1718,59 @@
}
}
+ int strModeToMode(String modeStr, PrintWriter err) {
+ switch (modeStr) {
+ case "allow":
+ return AppOpsManager.MODE_ALLOWED;
+ case "deny":
+ return AppOpsManager.MODE_ERRORED;
+ case "ignore":
+ return AppOpsManager.MODE_IGNORED;
+ case "default":
+ return AppOpsManager.MODE_DEFAULT;
+ }
+ try {
+ return Integer.parseInt(modeStr);
+ } catch (NumberFormatException e) {
+ }
+ err.println("Error: Mode " + modeStr + " is not valid");
+ return -1;
+ }
+
+ int parseUserOpMode(int defMode, PrintWriter err) throws RemoteException {
+ userId = UserHandle.USER_CURRENT;
+ opStr = null;
+ modeStr = null;
+ for (String argument; (argument = getNextArg()) != null;) {
+ if ("--user".equals(argument)) {
+ userId = UserHandle.parseUserArg(getNextArgRequired());
+ } else {
+ if (opStr == null) {
+ opStr = argument;
+ } else if (modeStr == null) {
+ modeStr = argument;
+ break;
+ }
+ }
+ }
+ if (opStr == null) {
+ err.println("Error: Operation not specified.");
+ return -1;
+ }
+ op = strOpToOp(opStr, err);
+ if (op < 0) {
+ return -1;
+ }
+ if (modeStr != null) {
+ if ((mode=strModeToMode(modeStr, err)) < 0) {
+ return -1;
+ }
+ } else {
+ mode = defMode;
+ }
+ return 0;
+ }
+
int parseUserPackageOp(boolean reqOp, PrintWriter err) throws RemoteException {
userId = UserHandle.USER_CURRENT;
packageName = null;
@@ -1742,6 +1832,8 @@
pw.println(" Set the mode for a particular application and operation.");
pw.println(" get [--user <USER_ID>] <PACKAGE> [<OP>]");
pw.println(" Return the mode for a particular application and optional operation.");
+ pw.println(" query-op [--user <USER_ID>] <OP> [<MODE>]");
+ pw.println(" Print all packages that currently have the given op in the given mode.");
pw.println(" reset [--user <USER_ID>] [<PACKAGE>]");
pw.println(" Reset the given application or all applications to default modes.");
pw.println(" write-settings");
@@ -1775,23 +1867,9 @@
return -1;
}
- final int mode;
- switch (modeStr) {
- case "allow":
- mode = AppOpsManager.MODE_ALLOWED;
- break;
- case "deny":
- mode = AppOpsManager.MODE_ERRORED;
- break;
- case "ignore":
- mode = AppOpsManager.MODE_IGNORED;
- break;
- case "default":
- mode = AppOpsManager.MODE_DEFAULT;
- break;
- default:
- err.println("Error: Mode " + modeStr + " is not valid,");
- return -1;
+ final int mode = shell.strModeToMode(modeStr, err);
+ if (mode < 0) {
+ return -1;
}
shell.mInterface.setMode(shell.op, shell.packageUid, shell.packageName, mode);
@@ -1856,6 +1934,34 @@
}
return 0;
}
+ case "query-op": {
+ int res = shell.parseUserOpMode(AppOpsManager.MODE_IGNORED, err);
+ if (res < 0) {
+ return res;
+ }
+ List<AppOpsManager.PackageOps> ops = shell.mInterface.getPackagesForOps(
+ new int[] {shell.op});
+ if (ops == null || ops.size() <= 0) {
+ pw.println("No operations.");
+ return 0;
+ }
+ for (int i=0; i<ops.size(); i++) {
+ final AppOpsManager.PackageOps pkg = ops.get(i);
+ boolean hasMatch = false;
+ final List<AppOpsManager.OpEntry> entries = ops.get(i).getOps();
+ for (int j=0; j<entries.size(); j++) {
+ AppOpsManager.OpEntry ent = entries.get(j);
+ if (ent.getOp() == shell.op && ent.getMode() == shell.mode) {
+ hasMatch = true;
+ break;
+ }
+ }
+ if (hasMatch) {
+ pw.println(pkg.getPackageName());
+ }
+ }
+ return 0;
+ }
case "reset": {
String packageName = null;
int userId = UserHandle.USER_CURRENT;
@@ -2103,6 +2209,7 @@
@Override
public void setUserRestrictions(Bundle restrictions, IBinder token, int userHandle) {
checkSystemUid("setUserRestrictions");
+ Preconditions.checkNotNull(restrictions);
Preconditions.checkNotNull(token);
final boolean[] opRestrictions = getOrCreateUserRestrictionsForToken(token, userHandle);
for (int i = 0; i < opRestrictions.length; ++i) {
@@ -2317,6 +2424,17 @@
}
}
+ private static String resolvePackageName(int uid, String packageName) {
+ if (uid == 0) {
+ return "root";
+ } else if (uid == Process.SHELL_UID) {
+ return "com.android.shell";
+ } else if (uid == Process.SYSTEM_UID && packageName == null) {
+ return "android";
+ }
+ return packageName;
+ }
+
private static String[] getPackagesForUid(int uid) {
String[] packageNames = null;
try {
diff --git a/services/core/java/com/android/server/BluetoothManagerService.java b/services/core/java/com/android/server/BluetoothManagerService.java
index 799a763..0a814ab 100644
--- a/services/core/java/com/android/server/BluetoothManagerService.java
+++ b/services/core/java/com/android/server/BluetoothManagerService.java
@@ -92,6 +92,7 @@
private static final int MESSAGE_BLUETOOTH_STATE_CHANGE = 60;
private static final int MESSAGE_TIMEOUT_BIND = 100;
private static final int MESSAGE_TIMEOUT_UNBIND = 101;
+ private static final int MESSAGE_GET_NAME_AND_ADDRESS = 200;
private static final int MESSAGE_USER_SWITCHED = 300;
private static final int MESSAGE_USER_UNLOCKED = 301;
private static final int MESSAGE_ADD_PROXY_DELAYED = 400;
@@ -599,8 +600,8 @@
sendEnableMsg(true);
}
return true;
-
}
+
public boolean enable() {
if ((Binder.getCallingUid() != Process.SYSTEM_UID) &&
(!checkIfCallerIsForegroundUser())) {
@@ -763,9 +764,8 @@
sendEnableMsg(mQuietEnableExternal);
} else if (!isNameAndAddressSet()) {
if (DBG) Slog.d(TAG, "Getting adapter name and address");
- enable();
- waitForOnOff(true, false);
- disable(true);
+ Message getMsg = mHandler.obtainMessage(MESSAGE_GET_NAME_AND_ADDRESS);
+ mHandler.sendMessage(getMsg);
}
}
@@ -1076,6 +1076,8 @@
private BluetoothServiceConnection mConnection = new BluetoothServiceConnection();
private class BluetoothHandler extends Handler {
+ boolean mGetNameAddressOnly = false;
+
public BluetoothHandler(Looper looper) {
super(looper);
}
@@ -1084,6 +1086,37 @@
public void handleMessage(Message msg) {
if (DBG) Slog.d (TAG, "Message: " + msg.what);
switch (msg.what) {
+ case MESSAGE_GET_NAME_AND_ADDRESS:
+ if (DBG) Slog.d(TAG, "MESSAGE_GET_NAME_AND_ADDRESS");
+ synchronized(mConnection) {
+ if ((mBluetooth == null) && (!mBinding)) {
+ if (DBG) Slog.d(TAG, "Binding to service to get name and address");
+ mGetNameAddressOnly = true;
+ Message timeoutMsg = mHandler.obtainMessage(MESSAGE_TIMEOUT_BIND);
+ mHandler.sendMessageDelayed(timeoutMsg, TIMEOUT_BIND_MS);
+ Intent i = new Intent(IBluetooth.class.getName());
+ if (!doBind(i, mConnection,
+ Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT,
+ UserHandle.CURRENT)) {
+ mHandler.removeMessages(MESSAGE_TIMEOUT_BIND);
+ } else {
+ mBinding = true;
+ }
+ } else if (mBluetooth != null) {
+ try {
+ storeNameAndAddress(mBluetooth.getName(),
+ mBluetooth.getAddress());
+ } catch (RemoteException re) {
+ Slog.e(TAG, "Unable to grab names", re);
+ }
+ if (mGetNameAddressOnly && !mEnable) {
+ unbindAndFinish();
+ }
+ mGetNameAddressOnly = false;
+ }
+ }
+ break;
+
case MESSAGE_ENABLE:
if (DBG) {
Slog.d(TAG, "MESSAGE_ENABLE: mBluetooth = " + mBluetooth);
@@ -1177,6 +1210,12 @@
mBluetoothBinder = service;
mBluetooth = IBluetooth.Stub.asInterface(service);
+ if (!isNameAndAddressSet()) {
+ Message getMsg = mHandler.obtainMessage(MESSAGE_GET_NAME_AND_ADDRESS);
+ mHandler.sendMessage(getMsg);
+ if (mGetNameAddressOnly) return;
+ }
+
try {
boolean enableHciSnoopLog = (Settings.Secure.getInt(mContentResolver,
Settings.Secure.BLUETOOTH_HCI_LOG, 0) == 1);
@@ -1187,15 +1226,6 @@
Slog.e(TAG,"Unable to call configHciSnoopLog", e);
}
- if (!isNameAndAddressSet()) {
- try {
- storeNameAndAddress(mBluetooth.getName(),
- mBluetooth.getAddress());
- } catch (RemoteException re) {
- Slog.e(TAG, "Unable to grab names", re);
- }
- }
-
//Register callback object
try {
mBluetooth.registerCallback(mBluetoothCallback);
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 95d3cc3..a4d6be5 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -371,8 +371,6 @@
private int mNetTransitionWakeLockTimeout;
private final PowerManager.WakeLock mPendingIntentWakeLock;
- private InetAddress mDefaultDns;
-
// used in DBG mode to track inet condition reports
private static final int INET_CONDITION_LOG_MAX_SIZE = 15;
private ArrayList mInetLog;
@@ -645,19 +643,6 @@
}
}
- // read our default dns server ip
- String dns = Settings.Global.getString(context.getContentResolver(),
- Settings.Global.DEFAULT_DNS_SERVER);
- if (dns == null || dns.length() == 0) {
- dns = context.getResources().getString(
- com.android.internal.R.string.config_default_dns_server);
- }
- try {
- mDefaultDns = NetworkUtils.numericToInetAddress(dns);
- } catch (IllegalArgumentException e) {
- loge("Error setting defaultDns using " + dns);
- }
-
mReleasePendingIntentDelayMs = Settings.Secure.getInt(context.getContentResolver(),
Settings.Secure.CONNECTIVITY_RELEASE_PENDING_INTENT_DELAY_MS, 5_000);
@@ -4149,14 +4134,8 @@
// }
updateTcpBufferSizes(networkAgent);
- // TODO: deprecate and remove mDefaultDns when we can do so safely. See http://b/18327075
- // In L, we used it only when the network had Internet access but provided no DNS servers.
- // For now, just disable it, and if disabling it doesn't break things, remove it.
- // final boolean useDefaultDns = networkAgent.networkCapabilities.hasCapability(
- // NET_CAPABILITY_INTERNET);
- final boolean useDefaultDns = false;
final boolean flushDns = updateRoutes(newLp, oldLp, netId);
- updateDnses(newLp, oldLp, netId, flushDns, useDefaultDns);
+ updateDnses(newLp, oldLp, netId, flushDns);
updateClat(newLp, oldLp, networkAgent);
if (isDefaultNetwork(networkAgent)) {
@@ -4260,16 +4239,9 @@
}
private void updateDnses(LinkProperties newLp, LinkProperties oldLp, int netId,
- boolean flush, boolean useDefaultDns) {
+ boolean flush) {
if (oldLp == null || (newLp.isIdenticalDnses(oldLp) == false)) {
Collection<InetAddress> dnses = newLp.getDnsServers();
- if (dnses.size() == 0 && mDefaultDns != null && useDefaultDns) {
- dnses = new ArrayList();
- dnses.add(mDefaultDns);
- if (DBG) {
- loge("no dns provided for netId " + netId + ", so using defaults");
- }
- }
if (DBG) log("Setting Dns servers for network " + netId + " to " + dnses);
try {
mNetd.setDnsServersForNetwork(netId, NetworkUtils.makeStrings(dnses),
diff --git a/services/core/java/com/android/server/DeviceIdleController.java b/services/core/java/com/android/server/DeviceIdleController.java
index 4749417..423f945 100644
--- a/services/core/java/com/android/server/DeviceIdleController.java
+++ b/services/core/java/com/android/server/DeviceIdleController.java
@@ -108,11 +108,12 @@
private static final boolean COMPRESS_TIME = false;
- private static final int EVENT_BUFFER_SIZE = 40;
+ private static final int EVENT_BUFFER_SIZE = 100;
private AlarmManager mAlarmManager;
private IBatteryStats mBatteryStats;
private PowerManagerInternal mLocalPowerManager;
+ private PowerManager mPowerManager;
private AlarmManagerService.LocalService mLocalAlarmManager;
private INetworkPolicyManager mNetworkPolicyManager;
private DisplayManager mDisplayManager;
@@ -168,16 +169,19 @@
private static final int LIGHT_STATE_ACTIVE = 0;
/** Device is inactive (screen off) and we are waiting to for the first light idle. */
private static final int LIGHT_STATE_INACTIVE = 1;
+ /** Device is about to go idle for the first time, wait for current work to complete. */
+ private static final int LIGHT_STATE_PRE_IDLE = 3;
/** Device is in the light idle state, trying to stay asleep as much as possible. */
- private static final int LIGHT_STATE_IDLE = 2;
+ private static final int LIGHT_STATE_IDLE = 4;
/** Device is in the light idle state, but temporarily out of idle to do regular maintenance. */
- private static final int LIGHT_STATE_IDLE_MAINTENANCE = 3;
+ private static final int LIGHT_STATE_IDLE_MAINTENANCE = 5;
/** Device light idle state is overriden, now applying deep doze state. */
- private static final int LIGHT_STATE_OVERRIDE = 4;
+ private static final int LIGHT_STATE_OVERRIDE = 6;
private static String lightStateToString(int state) {
switch (state) {
case LIGHT_STATE_ACTIVE: return "ACTIVE";
case LIGHT_STATE_INACTIVE: return "INACTIVE";
+ case LIGHT_STATE_PRE_IDLE: return "PRE_IDLE";
case LIGHT_STATE_IDLE: return "IDLE";
case LIGHT_STATE_IDLE_MAINTENANCE: return "IDLE_MAINTENANCE";
case LIGHT_STATE_OVERRIDE: return "OVERRIDE";
@@ -192,11 +196,13 @@
private long mNextAlarmTime;
private long mNextIdlePendingDelay;
private long mNextIdleDelay;
+ private long mNextLightIdleDelay;
private long mNextLightAlarmTime;
private long mCurIdleBudget;
private long mMaintenanceStartTime;
private int mActiveIdleOpCount;
+ private PowerManager.WakeLock mActiveIdleWakeLock;
private IBinder mDownloadServiceActive;
private boolean mJobsActive;
private boolean mAlarmsActive;
@@ -343,19 +349,18 @@
}
};
- private final AlarmManager.OnAlarmListener mMaintenanceMinCheckListener
- = new AlarmManager.OnAlarmListener() {
- @Override
- public void onAlarm() {
- synchronized (DeviceIdleController.this) {
- exitMaintenanceEarlyIfNeededLocked();
- }
- }
- };
-
private final BroadcastReceiver mIdleStartedDoneReceiver = new BroadcastReceiver() {
@Override public void onReceive(Context context, Intent intent) {
- decActiveIdleOps();
+ // When coming out of a deep idle, we will add in some delay before we allow
+ // the system to settle down and finish the maintenance window. This is
+ // to give a chance for any pending work to be scheduled.
+ if (PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED.equals(intent.getAction())) {
+ mHandler.sendEmptyMessageDelayed(MSG_FINISH_IDLE_OP,
+ mConstants.MIN_DEEP_MAINTENANCE_TIME);
+ } else {
+ mHandler.sendEmptyMessageDelayed(MSG_FINISH_IDLE_OP,
+ mConstants.MIN_LIGHT_MAINTENANCE_TIME);
+ }
}
};
@@ -477,7 +482,12 @@
*/
private final class Constants extends ContentObserver {
// Key names stored in the settings value.
+ private static final String KEY_LIGHT_IDLE_AFTER_INACTIVE_TIMEOUT
+ = "light_after_inactive_to";
+ private static final String KEY_LIGHT_PRE_IDLE_TIMEOUT = "light_pre_idle_to";
private static final String KEY_LIGHT_IDLE_TIMEOUT = "light_idle_to";
+ private static final String KEY_LIGHT_IDLE_FACTOR = "light_idle_factor";
+ private static final String KEY_LIGHT_MAX_IDLE_TIMEOUT = "light_max_idle_to";
private static final String KEY_LIGHT_IDLE_MAINTENANCE_MIN_BUDGET
= "light_idle_maintenance_min_budget";
private static final String KEY_LIGHT_IDLE_MAINTENANCE_MAX_BUDGET
@@ -505,14 +515,44 @@
"sms_temp_app_whitelist_duration";
/**
- * This is the time, after becoming inactive, that we will start going
- * in to light-weight idle mode.
+ * This is the time, after becoming inactive, that we go in to the first
+ * light-weight idle mode.
+ * @see Settings.Global#DEVICE_IDLE_CONSTANTS
+ * @see #KEY_LIGHT_IDLE_AFTER_INACTIVE_TIMEOUT
+ */
+ public long LIGHT_IDLE_AFTER_INACTIVE_TIMEOUT;
+
+ /**
+ * This is amount of time we will wait from the point where we decide we would
+ * like to go idle until we actually do, while waiting for jobs and other current
+ * activity to finish.
+ * @see Settings.Global#DEVICE_IDLE_CONSTANTS
+ * @see #KEY_LIGHT_PRE_IDLE_TIMEOUT
+ */
+ public long LIGHT_PRE_IDLE_TIMEOUT;
+
+ /**
+ * This is the initial time that we will run in idle maintenance mode.
* @see Settings.Global#DEVICE_IDLE_CONSTANTS
* @see #KEY_LIGHT_IDLE_TIMEOUT
*/
public long LIGHT_IDLE_TIMEOUT;
/**
+ * Scaling factor to apply to the light idle mode time each time we complete a cycle.
+ * @see Settings.Global#DEVICE_IDLE_CONSTANTS
+ * @see #KEY_LIGHT_IDLE_FACTOR
+ */
+ public float LIGHT_IDLE_FACTOR;
+
+ /**
+ * This is the maximum time we will run in idle maintenence mode.
+ * @see Settings.Global#DEVICE_IDLE_CONSTANTS
+ * @see #KEY_LIGHT_MAX_IDLE_TIMEOUT
+ */
+ public long LIGHT_MAX_IDLE_TIMEOUT;
+
+ /**
* This is the minimum amount of time we want to make available for maintenance mode
* when lightly idling. That is, we will always have at least this amount of time
* available maintenance before timing out and cutting off maintenance mode.
@@ -716,7 +756,16 @@
Slog.e(TAG, "Bad device idle settings", e);
}
+ LIGHT_IDLE_AFTER_INACTIVE_TIMEOUT = mParser.getLong(
+ KEY_LIGHT_IDLE_AFTER_INACTIVE_TIMEOUT,
+ !COMPRESS_TIME ? 5 * 60 * 1000L : 15 * 1000L);
+ LIGHT_PRE_IDLE_TIMEOUT = mParser.getLong(KEY_LIGHT_PRE_IDLE_TIMEOUT,
+ !COMPRESS_TIME ? 10 * 60 * 1000L : 30 * 1000L);
LIGHT_IDLE_TIMEOUT = mParser.getLong(KEY_LIGHT_IDLE_TIMEOUT,
+ !COMPRESS_TIME ? 5 * 60 * 1000L : 15 * 1000L);
+ LIGHT_IDLE_FACTOR = mParser.getFloat(KEY_LIGHT_IDLE_FACTOR,
+ 2f);
+ LIGHT_MAX_IDLE_TIMEOUT = mParser.getLong(KEY_LIGHT_MAX_IDLE_TIMEOUT,
!COMPRESS_TIME ? 15 * 60 * 1000L : 60 * 1000L);
LIGHT_IDLE_MAINTENANCE_MIN_BUDGET = mParser.getLong(
KEY_LIGHT_IDLE_MAINTENANCE_MIN_BUDGET,
@@ -770,10 +819,26 @@
void dump(PrintWriter pw) {
pw.println(" Settings:");
+ pw.print(" "); pw.print(KEY_LIGHT_IDLE_AFTER_INACTIVE_TIMEOUT); pw.print("=");
+ TimeUtils.formatDuration(LIGHT_IDLE_AFTER_INACTIVE_TIMEOUT, pw);
+ pw.println();
+
+ pw.print(" "); pw.print(KEY_LIGHT_PRE_IDLE_TIMEOUT); pw.print("=");
+ TimeUtils.formatDuration(LIGHT_PRE_IDLE_TIMEOUT, pw);
+ pw.println();
+
pw.print(" "); pw.print(KEY_LIGHT_IDLE_TIMEOUT); pw.print("=");
TimeUtils.formatDuration(LIGHT_IDLE_TIMEOUT, pw);
pw.println();
+ pw.print(" "); pw.print(KEY_LIGHT_IDLE_FACTOR); pw.print("=");
+ pw.print(LIGHT_IDLE_FACTOR);
+ pw.println();
+
+ pw.print(" "); pw.print(KEY_LIGHT_MAX_IDLE_TIMEOUT); pw.print("=");
+ TimeUtils.formatDuration(LIGHT_MAX_IDLE_TIMEOUT, pw);
+ pw.println();
+
pw.print(" "); pw.print(KEY_LIGHT_IDLE_MAINTENANCE_MIN_BUDGET); pw.print("=");
TimeUtils.formatDuration(LIGHT_IDLE_MAINTENANCE_MIN_BUDGET, pw);
pw.println();
@@ -892,6 +957,7 @@
static final int MSG_REPORT_ACTIVE = 5;
static final int MSG_TEMP_APP_WHITELIST_TIMEOUT = 6;
static final int MSG_REPORT_MAINTENANCE_ACTIVITY = 7;
+ static final int MSG_FINISH_IDLE_OP = 8;
final class MyHandler extends Handler {
MyHandler(Looper looper) {
@@ -996,6 +1062,9 @@
mMaintenanceActivityListeners.finishBroadcast();
}
} break;
+ case MSG_FINISH_IDLE_OP: {
+ decActiveIdleOps();
+ } break;
}
}
}
@@ -1252,6 +1321,10 @@
mAlarmManager = (AlarmManager) getContext().getSystemService(Context.ALARM_SERVICE);
mBatteryStats = BatteryStatsService.getService();
mLocalPowerManager = getLocalService(PowerManagerInternal.class);
+ mPowerManager = getContext().getSystemService(PowerManager.class);
+ mActiveIdleWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
+ "deviceidle_maint");
+ mActiveIdleWakeLock.setReferenceCounted(false);
mLocalAlarmManager = getLocalService(AlarmManagerService.LocalService.class);
mNetworkPolicyManager = INetworkPolicyManager.Stub.asInterface(
ServiceManager.getService(Context.NETWORK_POLICY_SERVICE));
@@ -1640,7 +1713,6 @@
mInactiveTimeout = mConstants.INACTIVE_TIMEOUT;
mCurIdleBudget = 0;
mMaintenanceStartTime = 0;
- mAlarmManager.cancel(mMaintenanceMinCheckListener);
resetIdleManagementLocked();
resetLightIdleManagementLocked();
addEvent(EVENT_NORMAL);
@@ -1663,7 +1735,7 @@
mLightState = LIGHT_STATE_INACTIVE;
if (DEBUG) Slog.d(TAG, "Moved from LIGHT_STATE_ACTIVE to LIGHT_STATE_INACTIVE");
resetLightIdleManagementLocked();
- scheduleLightAlarmLocked(mConstants.LIGHT_IDLE_TIMEOUT);
+ scheduleLightAlarmLocked(mConstants.LIGHT_IDLE_AFTER_INACTIVE_TIMEOUT);
EventLogTags.writeDeviceIdleLight(mLightState, "no activity");
}
}
@@ -1672,6 +1744,7 @@
void resetIdleManagementLocked() {
mNextIdlePendingDelay = 0;
mNextIdleDelay = 0;
+ mNextLightIdleDelay = 0;
cancelAlarmLocked();
cancelLocatingLocked();
stopMonitoringMotionLocked();
@@ -1704,7 +1777,19 @@
switch (mLightState) {
case LIGHT_STATE_INACTIVE:
mCurIdleBudget = mConstants.LIGHT_IDLE_MAINTENANCE_MIN_BUDGET;
+ // Reset the upcoming idle delays.
+ mNextLightIdleDelay = mConstants.LIGHT_IDLE_TIMEOUT;
mMaintenanceStartTime = 0;
+ if (!isOpsInactiveLocked()) {
+ // We have some active ops going on... give them a chance to finish
+ // before going in to our first idle.
+ mLightState = LIGHT_STATE_PRE_IDLE;
+ EventLogTags.writeDeviceIdleLight(mLightState, reason);
+ scheduleLightAlarmLocked(mConstants.LIGHT_PRE_IDLE_TIMEOUT);
+ break;
+ }
+ // Nothing active, fall through to immediately idle.
+ case LIGHT_STATE_PRE_IDLE:
case LIGHT_STATE_IDLE_MAINTENANCE:
if (mMaintenanceStartTime != 0) {
long duration = SystemClock.elapsedRealtime() - mMaintenanceStartTime;
@@ -1717,17 +1802,22 @@
}
}
mMaintenanceStartTime = 0;
- scheduleLightAlarmLocked(mConstants.LIGHT_IDLE_TIMEOUT);
+ scheduleLightAlarmLocked(mNextLightIdleDelay);
+ mNextLightIdleDelay = Math.min(mConstants.LIGHT_MAX_IDLE_TIMEOUT,
+ (long)(mNextLightIdleDelay * mConstants.LIGHT_IDLE_FACTOR));
+ if (mNextLightIdleDelay < mConstants.LIGHT_IDLE_TIMEOUT) {
+ mNextLightIdleDelay = mConstants.LIGHT_IDLE_TIMEOUT;
+ }
if (DEBUG) Slog.d(TAG, "Moved to LIGHT_STATE_IDLE.");
mLightState = LIGHT_STATE_IDLE;
EventLogTags.writeDeviceIdleLight(mLightState, reason);
addEvent(EVENT_LIGHT_IDLE);
mHandler.sendEmptyMessage(MSG_REPORT_IDLE_ON_LIGHT);
- mAlarmManager.cancel(mMaintenanceMinCheckListener);
break;
case LIGHT_STATE_IDLE:
// We have been idling long enough, now it is time to do some work.
mActiveIdleOpCount = 1;
+ mActiveIdleWakeLock.acquire();
mMaintenanceStartTime = SystemClock.elapsedRealtime();
if (mCurIdleBudget < mConstants.LIGHT_IDLE_MAINTENANCE_MIN_BUDGET) {
mCurIdleBudget = mConstants.LIGHT_IDLE_MAINTENANCE_MIN_BUDGET;
@@ -1741,9 +1831,6 @@
EventLogTags.writeDeviceIdleLight(mLightState, reason);
addEvent(EVENT_LIGHT_MAINTENANCE);
mHandler.sendEmptyMessage(MSG_REPORT_IDLE_OFF);
- mAlarmManager.setExact(AlarmManager.ELAPSED_REALTIME,
- mMaintenanceStartTime + mConstants.MIN_LIGHT_MAINTENANCE_TIME,
- "DeviceIdleController.maint-check", mMaintenanceMinCheckListener, mHandler);
break;
}
}
@@ -1820,6 +1907,7 @@
cancelAlarmLocked();
cancelLocatingLocked();
mAnyMotionDetector.stop();
+
case STATE_IDLE_MAINTENANCE:
scheduleAlarmLocked(mNextIdleDelay, true);
if (DEBUG) Slog.d(TAG, "Moved to STATE_IDLE. Next alarm in " + mNextIdleDelay +
@@ -1827,6 +1915,9 @@
mNextIdleDelay = (long)(mNextIdleDelay * mConstants.IDLE_FACTOR);
if (DEBUG) Slog.d(TAG, "Setting mNextIdleDelay = " + mNextIdleDelay);
mNextIdleDelay = Math.min(mNextIdleDelay, mConstants.MAX_IDLE_TIMEOUT);
+ if (mNextIdleDelay < mConstants.IDLE_TIMEOUT) {
+ mNextIdleDelay = mConstants.IDLE_TIMEOUT;
+ }
mState = STATE_IDLE;
if (mLightState != LIGHT_STATE_OVERRIDE) {
mLightState = LIGHT_STATE_OVERRIDE;
@@ -1835,24 +1926,24 @@
EventLogTags.writeDeviceIdle(mState, reason);
addEvent(EVENT_DEEP_IDLE);
mHandler.sendEmptyMessage(MSG_REPORT_IDLE_ON);
- mAlarmManager.cancel(mMaintenanceMinCheckListener);
break;
case STATE_IDLE:
// We have been idling long enough, now it is time to do some work.
mActiveIdleOpCount = 1;
+ mActiveIdleWakeLock.acquire();
scheduleAlarmLocked(mNextIdlePendingDelay, false);
if (DEBUG) Slog.d(TAG, "Moved from STATE_IDLE to STATE_IDLE_MAINTENANCE. " +
"Next alarm in " + mNextIdlePendingDelay + " ms.");
mMaintenanceStartTime = SystemClock.elapsedRealtime();
mNextIdlePendingDelay = Math.min(mConstants.MAX_IDLE_PENDING_TIMEOUT,
(long)(mNextIdlePendingDelay * mConstants.IDLE_PENDING_FACTOR));
+ if (mNextIdlePendingDelay < mConstants.IDLE_PENDING_TIMEOUT) {
+ mNextIdlePendingDelay = mConstants.IDLE_PENDING_TIMEOUT;
+ }
mState = STATE_IDLE_MAINTENANCE;
EventLogTags.writeDeviceIdle(mState, reason);
addEvent(EVENT_DEEP_MAINTENANCE);
mHandler.sendEmptyMessage(MSG_REPORT_IDLE_OFF);
- mAlarmManager.setExact(AlarmManager.ELAPSED_REALTIME,
- mMaintenanceStartTime + mConstants.MIN_DEEP_MAINTENANCE_TIME,
- "DeviceIdleController.maint-check", mMaintenanceMinCheckListener, mHandler);
break;
}
}
@@ -1868,6 +1959,7 @@
mActiveIdleOpCount--;
if (mActiveIdleOpCount <= 0) {
exitMaintenanceEarlyIfNeededLocked();
+ mActiveIdleWakeLock.release();
}
}
}
@@ -1939,10 +2031,15 @@
mHandler.sendMessage(msg);
}
+ boolean isOpsInactiveLocked() {
+ return mActiveIdleOpCount <= 0 && mDownloadServiceActive == null
+ && !mJobsActive && !mAlarmsActive;
+ }
+
void exitMaintenanceEarlyIfNeededLocked() {
- if (mState == STATE_IDLE_MAINTENANCE || mLightState == LIGHT_STATE_IDLE_MAINTENANCE) {
- if (mActiveIdleOpCount <= 0 && mDownloadServiceActive == null
- && !mJobsActive && !mAlarmsActive) {
+ if (mState == STATE_IDLE_MAINTENANCE || mLightState == LIGHT_STATE_IDLE_MAINTENANCE
+ || mLightState == LIGHT_STATE_PRE_IDLE) {
+ if (isOpsInactiveLocked()) {
final long now = SystemClock.elapsedRealtime();
if (DEBUG) {
StringBuilder sb = new StringBuilder();
@@ -1953,13 +2050,11 @@
Slog.d(TAG, sb.toString());
}
if (mState == STATE_IDLE_MAINTENANCE) {
- if (now >= (mMaintenanceStartTime + mConstants.MIN_DEEP_MAINTENANCE_TIME)) {
- stepIdleStateLocked("s:early");
- }
+ stepIdleStateLocked("s:early");
+ } else if (mLightState == LIGHT_STATE_PRE_IDLE) {
+ stepLightIdleStateLocked("s:predone");
} else {
- if (now >= (mMaintenanceStartTime + mConstants.MIN_LIGHT_MAINTENANCE_TIME)) {
- stepLightIdleStateLocked("s:early");
- }
+ stepLightIdleStateLocked("s:early");
}
}
}
@@ -2735,6 +2830,11 @@
TimeUtils.formatDuration(mNextIdleDelay, pw);
pw.println();
}
+ if (mNextLightIdleDelay != 0) {
+ pw.print(" mNextIdleDelay=");
+ TimeUtils.formatDuration(mNextLightIdleDelay, pw);
+ pw.println();
+ }
if (mNextLightAlarmTime != 0) {
pw.print(" mNextLightAlarmTime=");
TimeUtils.formatDuration(mNextLightAlarmTime, SystemClock.elapsedRealtime(), pw);
diff --git a/services/core/java/com/android/server/GraphicsStatsService.java b/services/core/java/com/android/server/GraphicsStatsService.java
index e29515f..ecbe1ca 100644
--- a/services/core/java/com/android/server/GraphicsStatsService.java
+++ b/services/core/java/com/android/server/GraphicsStatsService.java
@@ -51,7 +51,7 @@
* 2) ASHMEM_SIZE (for scratch space used during dumping)
* 3) ASHMEM_SIZE * HISTORY_SIZE
*
- * This is currently under 16KiB total memory in the worst case of
+ * This is currently under 20KiB total memory in the worst case of
* 20 processes in history + 10 unique active processes.
*
* @hide */
@@ -59,7 +59,7 @@
public static final String GRAPHICS_STATS_SERVICE = "graphicsstats";
private static final String TAG = "GraphicsStatsService";
- private static final int ASHMEM_SIZE = 296;
+ private static final int ASHMEM_SIZE = 464;
private static final int HISTORY_SIZE = 20;
private final Context mContext;
diff --git a/services/core/java/com/android/server/InputMethodManagerService.java b/services/core/java/com/android/server/InputMethodManagerService.java
index e042483..811e34e 100644
--- a/services/core/java/com/android/server/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/InputMethodManagerService.java
@@ -125,6 +125,7 @@
import android.widget.RadioButton;
import android.widget.Switch;
import android.widget.TextView;
+import android.widget.Toast;
import java.io.File;
import java.io.FileDescriptor;
@@ -452,6 +453,7 @@
private AlertDialog.Builder mDialogBuilder;
private AlertDialog mSwitchingDialog;
private View mSwitchingDialogTitleView;
+ private Toast mSubtypeSwitchedByShortCutToast;
private InputMethodInfo[] mIms;
private int[] mSubtypeIds;
private LocaleList mLastSystemLocales;
@@ -1715,8 +1717,9 @@
// exists in the IME switcher dialog. Might be OK to remove this condition once
// SHOW_IME_WITH_HARD_KEYBOARD settings finds a good place to live.
return true;
+ } else if ((visibility & InputMethodService.IME_VISIBLE) == 0) {
+ return false;
}
- if ((visibility & InputMethodService.IME_VISIBLE) == 0) return false;
List<InputMethodInfo> imis = mSettings.getEnabledInputMethodListLocked();
final int N = imis.size();
@@ -2951,6 +2954,27 @@
return;
}
setInputMethodLocked(nextSubtype.mImi.getId(), nextSubtype.mSubtypeId);
+ if (mSubtypeSwitchedByShortCutToast != null) {
+ mSubtypeSwitchedByShortCutToast.cancel();
+ mSubtypeSwitchedByShortCutToast = null;
+ }
+ if ((mImeWindowVis & InputMethodService.IME_VISIBLE) != 0) {
+ // IME window is shown. The user should be able to visually understand that the
+ // subtype is changed in most of cases. To avoid UI overlap, we do not show a toast
+ // in this case.
+ return;
+ }
+ final InputMethodInfo newInputMethodInfo = mMethodMap.get(mCurMethodId);
+ if (newInputMethodInfo == null) {
+ return;
+ }
+ final CharSequence toastText = InputMethodUtils.getImeAndSubtypeDisplayName(mContext,
+ newInputMethodInfo, mCurrentSubtype);
+ if (!TextUtils.isEmpty(toastText)) {
+ mSubtypeSwitchedByShortCutToast = Toast.makeText(mContext, toastText.toString(),
+ Toast.LENGTH_SHORT);
+ mSubtypeSwitchedByShortCutToast.show();
+ }
}
}
@@ -3220,16 +3244,6 @@
};
mDialogBuilder.setSingleChoiceItems(adapter, checkedItem, choiceListener);
- if (!isScreenLocked) {
- final OnClickListener positiveListener = new OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int whichButton) {
- showConfigureInputMethods();
- }
- };
- mDialogBuilder.setPositiveButton(
- com.android.internal.R.string.configure_input_methods, positiveListener);
- }
mSwitchingDialog = mDialogBuilder.create();
mSwitchingDialog.setCanceledOnTouchOutside(true);
mSwitchingDialog.getWindow().setType(
@@ -3832,6 +3846,22 @@
}
}
+ private static String imeWindowStatusToString(final int imeWindowVis) {
+ final StringBuilder sb = new StringBuilder();
+ boolean first = true;
+ if ((imeWindowVis & InputMethodService.IME_ACTIVE) != 0) {
+ sb.append("Active");
+ first = false;
+ }
+ if ((imeWindowVis & InputMethodService.IME_VISIBLE) != 0) {
+ if (!first) {
+ sb.append("|");
+ }
+ sb.append("Visible");
+ }
+ return sb.toString();
+ }
+
@Override
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
@@ -3879,6 +3909,7 @@
method = mCurMethod;
p.println(" mCurMethod=" + mCurMethod);
p.println(" mEnabledSession=" + mEnabledSession);
+ p.println(" mImeWindowVis=" + imeWindowStatusToString(mImeWindowVis));
p.println(" mShowRequested=" + mShowRequested
+ " mShowExplicitlyRequested=" + mShowExplicitlyRequested
+ " mShowForced=" + mShowForced
diff --git a/services/core/java/com/android/server/MountService.java b/services/core/java/com/android/server/MountService.java
index 45008dc..440d8b7 100644
--- a/services/core/java/com/android/server/MountService.java
+++ b/services/core/java/com/android/server/MountService.java
@@ -165,6 +165,7 @@
public void onStart() {
mMountService = new MountService(getContext());
publishBinderService("mount", mMountService);
+ mMountService.start();
}
@Override
@@ -430,9 +431,13 @@
= { "password", "default", "pattern", "pin" };
private final Context mContext;
+
private final NativeDaemonConnector mConnector;
private final NativeDaemonConnector mCryptConnector;
+ private final Thread mConnectorThread;
+ private final Thread mCryptConnectorThread;
+
private volatile boolean mSystemReady = false;
private volatile boolean mBootCompleted = false;
private volatile boolean mDaemonConnected = false;
@@ -1226,7 +1231,8 @@
}
final Intent intent = new Intent(DiskInfo.ACTION_DISK_SCANNED);
- intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
+ intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
+ | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
intent.putExtra(DiskInfo.EXTRA_DISK_ID, disk.id);
intent.putExtra(DiskInfo.EXTRA_VOLUME_COUNT, volumeCount);
mHandler.obtainMessage(H_INTERNAL_BROADCAST, intent).sendToTarget();
@@ -1241,6 +1247,11 @@
}
private void onVolumeCreatedLocked(VolumeInfo vol) {
+ if (mPms.isOnlyCoreApps()) {
+ Slog.d(TAG, "System booted in core-only mode; ignoring volume " + vol.getId());
+ return;
+ }
+
if (vol.type == VolumeInfo.TYPE_EMULATED) {
final StorageManager storage = mContext.getSystemService(StorageManager.class);
final VolumeInfo privateVol = storage.findPrivateForEmulated(vol);
@@ -1342,7 +1353,8 @@
intent.putExtra(VolumeInfo.EXTRA_VOLUME_ID, vol.id);
intent.putExtra(VolumeInfo.EXTRA_VOLUME_STATE, newState);
intent.putExtra(VolumeRecord.EXTRA_FS_UUID, vol.fsUuid);
- intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
+ intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
+ | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
mHandler.obtainMessage(H_INTERNAL_BROADCAST, intent).sendToTarget();
}
@@ -1494,17 +1506,13 @@
null);
mConnector.setDebug(true);
mConnector.setWarnIfHeld(mLock);
-
- Thread thread = new Thread(mConnector, VOLD_TAG);
- thread.start();
+ mConnectorThread = new Thread(mConnector, VOLD_TAG);
// Reuse parameters from first connector since they are tested and safe
mCryptConnector = new NativeDaemonConnector(this, "cryptd",
MAX_CONTAINERS * 2, CRYPTD_TAG, 25, null);
mCryptConnector.setDebug(true);
-
- Thread crypt_thread = new Thread(mCryptConnector, CRYPTD_TAG);
- crypt_thread.start();
+ mCryptConnectorThread = new Thread(mCryptConnector, CRYPTD_TAG);
final IntentFilter userFilter = new IntentFilter();
userFilter.addAction(Intent.ACTION_USER_ADDED);
@@ -1521,6 +1529,11 @@
}
}
+ private void start() {
+ mConnectorThread.start();
+ mCryptConnectorThread.start();
+ }
+
private void systemReady() {
mSystemReady = true;
mHandler.obtainMessage(H_SYSTEM_READY).sendToTarget();
diff --git a/services/core/java/com/android/server/NsdService.java b/services/core/java/com/android/server/NsdService.java
index 11aef17..a44b065 100644
--- a/services/core/java/com/android/server/NsdService.java
+++ b/services/core/java/com/android/server/NsdService.java
@@ -30,16 +30,14 @@
import android.os.Messenger;
import android.os.UserHandle;
import android.provider.Settings;
+import android.util.Base64;
import android.util.Slog;
import android.util.SparseArray;
import java.io.FileDescriptor;
import java.io.PrintWriter;
-import java.io.UnsupportedEncodingException;
import java.net.InetAddress;
import java.util.HashMap;
-import java.util.Locale;
-import java.util.Map;
import java.util.concurrent.CountDownLatch;
import com.android.internal.util.AsyncChannel;
@@ -492,6 +490,7 @@
clientInfo.mResolvedService.setServiceName(name);
clientInfo.mResolvedService.setServiceType(type);
clientInfo.mResolvedService.setPort(Integer.parseInt(cooked[4]));
+ clientInfo.mResolvedService.setTxtRecords(cooked[6]);
stopResolveService(id);
removeRequestMap(clientId, id, clientInfo);
@@ -708,20 +707,9 @@
if (DBG) Slog.d(TAG, "registerService: " + regId + " " + service);
try {
Command cmd = new Command("mdnssd", "register", regId, service.getServiceName(),
- service.getServiceType(), service.getPort());
-
- // Add TXT records as additional arguments.
- Map<String, byte[]> txtRecords = service.getAttributes();
- for (String key : txtRecords.keySet()) {
- try {
- // TODO: Send encoded TXT record as bytes once NDC/netd supports binary data.
- byte[] recordValue = txtRecords.get(key);
- cmd.appendArg(String.format(Locale.US, "%s=%s", key,
- recordValue != null ? new String(recordValue, "UTF_8") : ""));
- } catch (UnsupportedEncodingException e) {
- Slog.e(TAG, "Failed to encode txtRecord " + e);
- }
- }
+ service.getServiceType(), service.getPort(),
+ Base64.encodeToString(service.getTxtRecord(), Base64.DEFAULT)
+ .replace("\n", ""));
mNativeConnector.execute(cmd);
} catch(NativeDaemonConnectorException e) {
diff --git a/services/core/java/com/android/server/RecoverySystemService.java b/services/core/java/com/android/server/RecoverySystemService.java
index d284d07..276687f 100644
--- a/services/core/java/com/android/server/RecoverySystemService.java
+++ b/services/core/java/com/android/server/RecoverySystemService.java
@@ -79,7 +79,7 @@
uncryptFile.write(filename + "\n");
} catch (IOException e) {
Slog.e(TAG, "IOException when writing \"" + RecoverySystem.UNCRYPT_PACKAGE_FILE +
- "\": " + e.getMessage());
+ "\": ", e);
return false;
}
@@ -94,8 +94,11 @@
}
// Read the status from the socket.
- try (DataInputStream dis = new DataInputStream(socket.getInputStream());
- DataOutputStream dos = new DataOutputStream(socket.getOutputStream())) {
+ DataInputStream dis = null;
+ DataOutputStream dos = null;
+ try {
+ dis = new DataInputStream(socket.getInputStream());
+ dos = new DataOutputStream(socket.getOutputStream());
int lastStatus = Integer.MIN_VALUE;
while (true) {
int status = dis.readInt();
@@ -111,7 +114,7 @@
if (listener != null) {
try {
listener.onProgress(status);
- } catch (RemoteException unused) {
+ } catch (RemoteException ignored) {
Slog.w(TAG, "RemoteException when posting progress");
}
}
@@ -121,7 +124,6 @@
// waits for the ack so the socket won't be
// destroyed before we receive the code.
dos.writeInt(0);
- dos.flush();
break;
}
} else {
@@ -131,14 +133,15 @@
// for the ack so the socket won't be destroyed before
// we receive the code.
dos.writeInt(0);
- dos.flush();
return false;
}
}
} catch (IOException e) {
- Slog.e(TAG, "IOException when reading status: " + e);
+ Slog.e(TAG, "IOException when reading status: ", e);
return false;
} finally {
+ IoUtils.closeQuietly(dis);
+ IoUtils.closeQuietly(dos);
IoUtils.closeQuietly(socket);
}
@@ -169,11 +172,11 @@
LocalSocketAddress.Namespace.RESERVED));
done = true;
break;
- } catch (IOException unused) {
+ } catch (IOException ignored) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
- Slog.w(TAG, "Interrupted: " + e);
+ Slog.w(TAG, "Interrupted: ", e);
}
}
}
@@ -200,8 +203,12 @@
return false;
}
- try (DataInputStream dis = new DataInputStream(socket.getInputStream());
- DataOutputStream dos = new DataOutputStream(socket.getOutputStream())) {
+ DataInputStream dis = null;
+ DataOutputStream dos = null;
+ try {
+ dis = new DataInputStream(socket.getInputStream());
+ dos = new DataOutputStream(socket.getOutputStream());
+
// Send the BCB commands if it's to setup BCB.
if (isSetup) {
dos.writeInt(command.length());
@@ -215,7 +222,6 @@
// Ack receipt of the status code. uncrypt waits for the ack so
// the socket won't be destroyed before we receive the code.
dos.writeInt(0);
- dos.flush();
if (status == 100) {
Slog.i(TAG, "uncrypt " + (isSetup ? "setup" : "clear") +
@@ -226,9 +232,11 @@
return false;
}
} catch (IOException e) {
- Slog.e(TAG, "IOException when getting output stream: " + e);
+ Slog.e(TAG, "IOException when communicating with uncrypt: ", e);
return false;
} finally {
+ IoUtils.closeQuietly(dis);
+ IoUtils.closeQuietly(dos);
IoUtils.closeQuietly(socket);
}
diff --git a/services/core/java/com/android/server/ThermalObserver.java b/services/core/java/com/android/server/ThermalObserver.java
deleted file mode 100644
index aee28fb..0000000
--- a/services/core/java/com/android/server/ThermalObserver.java
+++ /dev/null
@@ -1,146 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.server;
-
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.PackageManager;
-import android.os.Binder;
-import android.os.Handler;
-import android.os.Message;
-import android.os.PowerManager;
-import android.os.UEventObserver;
-import android.os.UserHandle;
-
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
-
-/**
- * ThermalObserver for monitoring temperature changes.
- */
-public class ThermalObserver extends SystemService {
- private static final String TAG = "ThermalObserver";
-
- private static final String CALLSTATE_UEVENT_MATCH =
- "DEVPATH=/devices/virtual/switch/thermalstate";
-
- private static final int MSG_THERMAL_STATE_CHANGED = 0;
-
- private static final int SWITCH_STATE_NORMAL = 0;
- private static final int SWITCH_STATE_WARNING = 1;
- private static final int SWITCH_STATE_EXCEEDED = 2;
-
- private final PowerManager mPowerManager;
- private final PowerManager.WakeLock mWakeLock;
-
- private final Object mLock = new Object();
- private Integer mLastState;
-
- private final UEventObserver mThermalWarningObserver = new UEventObserver() {
- @Override
- public void onUEvent(UEventObserver.UEvent event) {
- updateLocked(Integer.parseInt(event.get("SWITCH_STATE")));
- }
- };
-
- private final Handler mHandler = new Handler(true /*async*/) {
- @Override
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case MSG_THERMAL_STATE_CHANGED:
- handleThermalStateChange(msg.arg1);
- mWakeLock.release();
- break;
- }
- }
- };
-
- public ThermalObserver(Context context) {
- super(context);
- mPowerManager = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
- mWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
-
- mThermalWarningObserver.startObserving(CALLSTATE_UEVENT_MATCH);
- }
-
- private void updateLocked(int state) {
- Message message = new Message();
- message.what = MSG_THERMAL_STATE_CHANGED;
- message.arg1 = state;
-
- mWakeLock.acquire();
- mHandler.sendMessage(message);
- }
-
- private void handleThermalStateChange(int state) {
- synchronized (mLock) {
- mLastState = state;
- Intent intent = new Intent(Intent.ACTION_THERMAL_EVENT);
- intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
-
- final int thermalState;
-
- switch (state) {
- case SWITCH_STATE_WARNING:
- thermalState = Intent.EXTRA_THERMAL_STATE_WARNING;
- break;
- case SWITCH_STATE_EXCEEDED:
- thermalState = Intent.EXTRA_THERMAL_STATE_EXCEEDED;
- break;
- case SWITCH_STATE_NORMAL:
- default:
- thermalState = Intent.EXTRA_THERMAL_STATE_NORMAL;
- break;
- }
-
- intent.putExtra(Intent.EXTRA_THERMAL_STATE, thermalState);
-
- getContext().sendBroadcastAsUser(intent, UserHandle.ALL);
- }
- }
-
- @Override
- public void onStart() {
- publishBinderService(TAG, new BinderService());
- }
-
- private final class BinderService extends Binder {
- @Override
- protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- if (getContext().checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
- != PackageManager.PERMISSION_GRANTED) {
- pw.println("Permission Denial: can't dump thermal observer service from from pid="
- + Binder.getCallingPid()
- + ", uid=" + Binder.getCallingUid());
- return;
- }
-
- final long ident = Binder.clearCallingIdentity();
- try {
- synchronized (mLock) {
- if (args == null || args.length == 0 || "-a".equals(args[0])) {
- pw.println("Current Thermal Observer Service state:");
- pw.println(" last state change: "
- + (mLastState != null ? mLastState : "none"));
- }
- }
- } finally {
- Binder.restoreCallingIdentity(ident);
- }
- }
- }
-}
diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
index 1632f92..8a0a62a 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
@@ -65,6 +65,7 @@
import android.os.Binder;
import android.os.Bundle;
import android.os.Environment;
+import android.os.FileUtils;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
@@ -75,11 +76,13 @@
import android.os.SystemClock;
import android.os.UserHandle;
import android.os.UserManager;
+import android.os.storage.StorageManager;
import android.text.TextUtils;
import android.util.Log;
import android.util.Pair;
import android.util.Slog;
import android.util.SparseArray;
+import android.util.SparseBooleanArray;
import com.android.internal.R;
import com.android.internal.util.ArrayUtils;
@@ -91,6 +94,7 @@
import java.io.File;
import java.io.FileDescriptor;
+import java.io.IOException;
import java.io.PrintWriter;
import java.security.GeneralSecurityException;
import java.security.MessageDigest;
@@ -107,7 +111,6 @@
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
-import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
@@ -126,7 +129,9 @@
private static final String TAG = "AccountManagerService";
private static final String DATABASE_NAME = "accounts.db";
- private static final int DATABASE_VERSION = 9;
+ private static final int PRE_N_DATABASE_VERSION = 9;
+ private static final int CE_DATABASE_VERSION = 10;
+ private static final int DE_DATABASE_VERSION = 1;
private static final int MAX_DEBUG_DB_SIZE = 64;
@@ -176,6 +181,15 @@
private static final String META_VALUE = "value";
private static final String TABLE_SHARED_ACCOUNTS = "shared_accounts";
+ private static final String SHARED_ACCOUNTS_ID = "_id";
+
+ private static final String PRE_N_DATABASE_NAME = "accounts.db";
+ private static final String CE_DATABASE_NAME = "accounts_ce.db";
+ private static final String DE_DATABASE_NAME = "accounts_de.db";
+ private static final String CE_DB_PREFIX = "ceDb.";
+ private static final String CE_TABLE_ACCOUNTS = CE_DB_PREFIX + TABLE_ACCOUNTS;
+ private static final String CE_TABLE_AUTHTOKENS = CE_DB_PREFIX + TABLE_AUTHTOKENS;
+ private static final String CE_TABLE_EXTRAS = CE_DB_PREFIX + TABLE_EXTRAS;
private static final String[] ACCOUNT_TYPE_COUNT_PROJECTION =
new String[] { ACCOUNTS_TYPE, ACCOUNTS_TYPE_COUNT};
@@ -214,7 +228,7 @@
static class UserAccounts {
private final int userId;
- private final DatabaseHelper openHelper;
+ private final DeDatabaseHelper openHelper;
private final HashMap<Pair<Pair<Account, String>, Integer>, Integer>
credentialsPermissionNotificationIds =
new HashMap<Pair<Pair<Account, String>, Integer>, Integer>();
@@ -255,15 +269,15 @@
UserAccounts(Context context, int userId) {
this.userId = userId;
synchronized (cacheLock) {
- openHelper = new DatabaseHelper(context, userId);
+ openHelper = DeDatabaseHelper.create(context, userId);
}
}
}
- private final SparseArray<UserAccounts> mUsers = new SparseArray<UserAccounts>();
+ private final SparseArray<UserAccounts> mUsers = new SparseArray<>();
+ private final SparseBooleanArray mUnlockedUsers = new SparseBooleanArray();
- private static AtomicReference<AccountManagerService> sThis =
- new AtomicReference<AccountManagerService>();
+ private static AtomicReference<AccountManagerService> sThis = new AtomicReference<>();
private static final Account[] EMPTY_ACCOUNT_ARRAY = new Account[]{};
/**
@@ -381,6 +395,11 @@
*/
private void validateAccountsInternal(
UserAccounts accounts, boolean invalidateAuthenticatorCache) {
+ if (Log.isLoggable(TAG, Log.DEBUG)) {
+ Log.d(TAG, "validateAccountsInternal " + accounts.userId
+ + " isCeDatabaseAttached=" + accounts.openHelper.isCeDatabaseAttached()
+ + " userLocked=" + mUnlockedUsers.get(accounts.userId));
+ }
if (invalidateAuthenticatorCache) {
mAuthenticatorCache.invalidateCache(accounts.userId);
}
@@ -453,8 +472,7 @@
null, null, null, null, ACCOUNTS_ID);
try {
accounts.accountCache.clear();
- final HashMap<String, ArrayList<String>> accountNamesByType =
- new LinkedHashMap<String, ArrayList<String>>();
+ final HashMap<String, ArrayList<String>> accountNamesByType = new LinkedHashMap<>();
while (cursor.moveToNext()) {
final long accountId = cursor.getLong(0);
final String accountType = cursor.getString(1);
@@ -482,15 +500,12 @@
accountNames.add(accountName);
}
}
- for (Map.Entry<String, ArrayList<String>> cur
- : accountNamesByType.entrySet()) {
+ for (Map.Entry<String, ArrayList<String>> cur : accountNamesByType.entrySet()) {
final String accountType = cur.getKey();
final ArrayList<String> accountNames = cur.getValue();
final Account[] accountsForType = new Account[accountNames.size()];
- int i = 0;
- for (String accountName : accountNames) {
- accountsForType[i] = new Account(accountName, accountType);
- ++i;
+ for (int i = 0; i < accountsForType.length; i++) {
+ accountsForType[i] = new Account(accountNames.get(i), accountType);
}
accounts.accountCache.put(accountType, accountsForType);
}
@@ -522,12 +537,25 @@
protected UserAccounts getUserAccounts(int userId) {
synchronized (mUsers) {
UserAccounts accounts = mUsers.get(userId);
+ boolean validateAccounts = false;
if (accounts == null) {
accounts = new UserAccounts(mContext, userId);
initializeDebugDbSizeAndCompileSqlStatementForLogging(
accounts.openHelper.getWritableDatabase(), accounts);
mUsers.append(userId, accounts);
purgeOldGrants(accounts);
+ validateAccounts = true;
+ }
+ // open CE database if necessary
+ if (!accounts.openHelper.isCeDatabaseAttached() && mUnlockedUsers.get(userId)) {
+ Log.i(TAG, "User " + userId + " is unlocked - opening CE database");
+ synchronized (accounts.cacheLock) {
+ CeDatabaseHelper.create(mContext, userId);
+ accounts.openHelper.attachCeDatabase();
+ }
+ // TODO Synchronize accounts by removing CE account not available in DE
+ }
+ if (validateAccounts) {
validateAccountsInternal(accounts, true /* invalidateAuthenticatorCache */);
}
return accounts;
@@ -571,27 +599,51 @@
if (userId < 1) return;
UserAccounts accounts;
+ boolean userUnlocked;
synchronized (mUsers) {
accounts = mUsers.get(userId);
mUsers.remove(userId);
+ userUnlocked = mUnlockedUsers.get(userId);
+ mUnlockedUsers.delete(userId);
}
- if (accounts == null) {
- File dbFile = new File(getDatabaseName(userId));
- dbFile.delete();
- return;
+ if (accounts != null) {
+ synchronized (accounts.cacheLock) {
+ accounts.openHelper.close();
+ }
}
+ Log.i(TAG, "Removing database files for user " + userId);
+ File dbFile = new File(getDeDatabaseName(userId));
- synchronized (accounts.cacheLock) {
- accounts.openHelper.close();
- File dbFile = new File(getDatabaseName(userId));
- dbFile.delete();
+ deleteDbFileWarnIfFailed(dbFile);
+ // Remove CE file if user is unlocked, or FBE is not enabled
+ boolean fbeEnabled = StorageManager.isFileEncryptedNativeOrEmulated();
+ if (!fbeEnabled || userUnlocked) {
+ File ceDb = new File(getCeDatabaseName(userId));
+ if (ceDb.exists()) {
+ deleteDbFileWarnIfFailed(ceDb);
+ }
+ }
+ }
+
+ private static void deleteDbFileWarnIfFailed(File dbFile) {
+ if (!SQLiteDatabase.deleteDatabase(dbFile)) {
+ Log.w(TAG, "Database at " + dbFile + " was not deleted successfully");
}
}
private void onUserUnlocked(Intent intent) {
int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG, "onUserUnlocked " + userId);
+ }
+ synchronized (mUsers) {
+ mUnlockedUsers.put(userId, true);
+ }
if (userId < 1) return;
+ syncSharedAccounts(userId);
+ }
+ private void syncSharedAccounts(int userId) {
// Check if there's a shared account that needs to be created as an account
Account[] sharedAccounts = getSharedAccountsAsUser(userId);
if (sharedAccounts == null || sharedAccounts.length == 0) return;
@@ -645,20 +697,15 @@
if (account == null) {
return null;
}
+ if (!isUserUnlocked(accounts.userId)) {
+ Log.w(TAG, "Password is not available - user " + accounts.userId + " data is locked");
+ return null;
+ }
synchronized (accounts.cacheLock) {
- final SQLiteDatabase db = accounts.openHelper.getReadableDatabase();
- Cursor cursor = db.query(TABLE_ACCOUNTS, new String[]{ACCOUNTS_PASSWORD},
- ACCOUNTS_NAME + "=? AND " + ACCOUNTS_TYPE+ "=?",
- new String[]{account.name, account.type}, null, null, null);
- try {
- if (cursor.moveToNext()) {
- return cursor.getString(0);
- }
- return null;
- } finally {
- cursor.close();
- }
+ final SQLiteDatabase db = accounts.openHelper.getReadableDatabaseUserIsUnlocked();
+ return CeDatabaseHelper.findAccountPasswordByNameAndType(db, account.name,
+ account.type);
}
}
@@ -699,7 +746,7 @@
try {
if (cursor.moveToNext()) {
String previousName = cursor.getString(0);
- previousNameRef = new AtomicReference<String>(previousName);
+ previousNameRef = new AtomicReference<>(previousName);
accounts.previousNameCache.put(account, previousNameRef);
return previousName;
} else {
@@ -735,7 +782,12 @@
long identityToken = clearCallingIdentity();
try {
UserAccounts accounts = getUserAccounts(userId);
- return readUserDataInternal(accounts, account, key);
+ synchronized (accounts.cacheLock) {
+ if (!accountExistsCacheLocked(accounts, account)) {
+ return null;
+ }
+ return readUserDataInternalLocked(accounts, account, key);
+ }
} finally {
restoreCallingIdentity(identityToken);
}
@@ -825,7 +877,7 @@
long identityToken = clearCallingIdentity();
try {
UserAccounts accounts = getUserAccounts(userId);
- return addAccountInternal(accounts, account, password, extras, false, callingUid);
+ return addAccountInternal(accounts, account, password, extras, callingUid);
} finally {
restoreCallingIdentity(identityToken);
}
@@ -999,17 +1051,22 @@
}
private boolean addAccountInternal(UserAccounts accounts, Account account, String password,
- Bundle extras, boolean restricted, int callingUid) {
+ Bundle extras, int callingUid) {
Bundle.setDefusable(extras, true);
if (account == null) {
return false;
}
+ if (!isUserUnlocked(accounts.userId)) {
+ Log.w(TAG, "Account " + account + " cannot be added - user " + accounts.userId
+ + " is locked. callingUid=" + callingUid);
+ return false;
+ }
synchronized (accounts.cacheLock) {
- final SQLiteDatabase db = accounts.openHelper.getWritableDatabase();
+ final SQLiteDatabase db = accounts.openHelper.getWritableDatabaseUserIsUnlocked();
db.beginTransaction();
try {
long numMatches = DatabaseUtils.longForQuery(db,
- "select count(*) from " + TABLE_ACCOUNTS
+ "select count(*) from " + CE_TABLE_ACCOUNTS
+ " WHERE " + ACCOUNTS_NAME + "=? AND " + ACCOUNTS_TYPE+ "=?",
new String[]{account.name, account.type});
if (numMatches > 0) {
@@ -1021,13 +1078,24 @@
values.put(ACCOUNTS_NAME, account.name);
values.put(ACCOUNTS_TYPE, account.type);
values.put(ACCOUNTS_PASSWORD, password);
- values.put(ACCOUNTS_LAST_AUTHENTICATE_TIME_EPOCH_MILLIS, System.currentTimeMillis());
- long accountId = db.insert(TABLE_ACCOUNTS, ACCOUNTS_NAME, values);
+ long accountId = db.insert(CE_TABLE_ACCOUNTS, ACCOUNTS_NAME, values);
if (accountId < 0) {
Log.w(TAG, "insertAccountIntoDatabase: " + account
+ ", skipping the DB insert failed");
return false;
}
+ // Insert into DE table
+ values = new ContentValues();
+ values.put(ACCOUNTS_ID, accountId);
+ values.put(ACCOUNTS_NAME, account.name);
+ values.put(ACCOUNTS_TYPE, account.type);
+ values.put(ACCOUNTS_LAST_AUTHENTICATE_TIME_EPOCH_MILLIS,
+ System.currentTimeMillis());
+ if (db.insert(TABLE_ACCOUNTS, ACCOUNTS_NAME, values) < 0) {
+ Log.w(TAG, "insertAccountIntoDatabase: " + account
+ + ", skipping the DB insert failed");
+ return false;
+ }
if (extras != null) {
for (String key : extras.keySet()) {
final String value = extras.getString(key);
@@ -1055,6 +1123,12 @@
return true;
}
+ private boolean isUserUnlocked(int userId) {
+ synchronized (mUsers) {
+ return mUnlockedUsers.get(userId);
+ }
+ }
+
/**
* Adds the account to all linked restricted users as shared accounts. If the user is currently
* running, then clone the account too.
@@ -1079,7 +1153,7 @@
values.put(EXTRAS_KEY, key);
values.put(EXTRAS_ACCOUNTS_ID, accountId);
values.put(EXTRAS_VALUE, value);
- return db.insert(TABLE_EXTRAS, EXTRAS_KEY, values);
+ return db.insert(CE_TABLE_EXTRAS, EXTRAS_KEY, values);
}
@Override
@@ -1226,17 +1300,19 @@
}
}
synchronized (accounts.cacheLock) {
- final SQLiteDatabase db = accounts.openHelper.getWritableDatabase();
+ final SQLiteDatabase db = accounts.openHelper.getWritableDatabaseUserIsUnlocked();
db.beginTransaction();
boolean isSuccessful = false;
Account renamedAccount = new Account(newName, accountToRename.type);
try {
- final ContentValues values = new ContentValues();
- values.put(ACCOUNTS_NAME, newName);
- values.put(ACCOUNTS_PREVIOUS_NAME, accountToRename.name);
final long accountId = getAccountIdLocked(db, accountToRename);
if (accountId >= 0) {
+ final ContentValues values = new ContentValues();
+ values.put(ACCOUNTS_NAME, newName);
final String[] argsAccountId = { String.valueOf(accountId) };
+ db.update(CE_TABLE_ACCOUNTS, values, ACCOUNTS_ID + "=?", argsAccountId);
+ // Update NAME/PREVIOUS_NAME in DE accounts table
+ values.put(ACCOUNTS_PREVIOUS_NAME, accountToRename.name);
db.update(TABLE_ACCOUNTS, values, ACCOUNTS_ID + "=?", argsAccountId);
db.setTransactionSuccessful();
isSuccessful = true;
@@ -1332,7 +1408,7 @@
* authenticator. This will let users remove accounts (via Settings in the system) but not
* arbitrary applications (like competing authenticators).
*/
- UserHandle user = new UserHandle(userId);
+ UserHandle user = UserHandle.of(userId);
if (!isAccountManagedByCaller(account.type, callingUid, user.getIdentifier())
&& !isSystemUid(callingUid)) {
String msg = String.format(
@@ -1467,13 +1543,17 @@
}
private boolean removeAccountInternal(UserAccounts accounts, Account account, int callingUid) {
+ // For now user is required to be unlocked. TODO: Handle both cases in the future
int deleted;
synchronized (accounts.cacheLock) {
- final SQLiteDatabase db = accounts.openHelper.getWritableDatabase();
+ final SQLiteDatabase db = accounts.openHelper.getWritableDatabaseUserIsUnlocked();
final long accountId = getAccountIdLocked(db, account);
deleted = db.delete(TABLE_ACCOUNTS, ACCOUNTS_NAME + "=? AND " + ACCOUNTS_TYPE
+ "=?",
new String[]{account.name, account.type});
+ // Delete from CE table
+ db.delete(CE_TABLE_ACCOUNTS, ACCOUNTS_NAME + "=? AND " + ACCOUNTS_TYPE + "=?",
+ new String[]{account.name, account.type});
removeAccountFromCacheLocked(accounts, account);
sendAccountsChangedBroadcast(accounts.userId);
@@ -1512,7 +1592,7 @@
try {
UserAccounts accounts = getUserAccounts(userId);
synchronized (accounts.cacheLock) {
- final SQLiteDatabase db = accounts.openHelper.getWritableDatabase();
+ final SQLiteDatabase db = accounts.openHelper.getWritableDatabaseUserIsUnlocked();
db.beginTransaction();
try {
invalidateAuthTokenLocked(accounts, db, accountType, authToken);
@@ -1544,22 +1624,22 @@
return;
}
Cursor cursor = db.rawQuery(
- "SELECT " + TABLE_AUTHTOKENS + "." + AUTHTOKENS_ID
- + ", " + TABLE_ACCOUNTS + "." + ACCOUNTS_NAME
- + ", " + TABLE_AUTHTOKENS + "." + AUTHTOKENS_TYPE
- + " FROM " + TABLE_ACCOUNTS
- + " JOIN " + TABLE_AUTHTOKENS
- + " ON " + TABLE_ACCOUNTS + "." + ACCOUNTS_ID
- + " = " + AUTHTOKENS_ACCOUNTS_ID
- + " WHERE " + AUTHTOKENS_AUTHTOKEN + " = ? AND "
- + TABLE_ACCOUNTS + "." + ACCOUNTS_TYPE + " = ?",
+ "SELECT " + CE_TABLE_AUTHTOKENS + "." + AUTHTOKENS_ID
+ + ", " + CE_TABLE_ACCOUNTS + "." + ACCOUNTS_NAME
+ + ", " + CE_TABLE_AUTHTOKENS + "." + AUTHTOKENS_TYPE
+ + " FROM " + CE_TABLE_ACCOUNTS
+ + " JOIN " + CE_TABLE_AUTHTOKENS
+ + " ON " + CE_TABLE_ACCOUNTS + "." + ACCOUNTS_ID
+ + " = " + CE_TABLE_AUTHTOKENS + "." + AUTHTOKENS_ACCOUNTS_ID
+ + " WHERE " + CE_TABLE_AUTHTOKENS + "." + AUTHTOKENS_AUTHTOKEN
+ + " = ? AND " + CE_TABLE_ACCOUNTS + "." + ACCOUNTS_TYPE + " = ?",
new String[]{authToken, accountType});
try {
while (cursor.moveToNext()) {
long authTokenId = cursor.getLong(0);
String accountName = cursor.getString(1);
String authTokenType = cursor.getString(2);
- db.delete(TABLE_AUTHTOKENS, AUTHTOKENS_ID + "=" + authTokenId, null);
+ db.delete(CE_TABLE_AUTHTOKENS, AUTHTOKENS_ID + "=" + authTokenId, null);
writeAuthTokenIntoCacheLocked(
accounts,
db,
@@ -1585,7 +1665,7 @@
return;
}
cancelNotification(getSigninRequiredNotificationId(accounts, account),
- new UserHandle(accounts.userId));
+ UserHandle.of(accounts.userId));
synchronized (accounts.cacheLock) {
accounts.accountTokenCaches.put(
account, token, tokenType, callerPkg, callerSigDigest, expiryMillis);
@@ -1598,23 +1678,23 @@
return false;
}
cancelNotification(getSigninRequiredNotificationId(accounts, account),
- new UserHandle(accounts.userId));
+ UserHandle.of(accounts.userId));
synchronized (accounts.cacheLock) {
- final SQLiteDatabase db = accounts.openHelper.getWritableDatabase();
+ final SQLiteDatabase db = accounts.openHelper.getWritableDatabaseUserIsUnlocked();
db.beginTransaction();
try {
long accountId = getAccountIdLocked(db, account);
if (accountId < 0) {
return false;
}
- db.delete(TABLE_AUTHTOKENS,
+ db.delete(CE_TABLE_AUTHTOKENS,
AUTHTOKENS_ACCOUNTS_ID + "=" + accountId + " AND " + AUTHTOKENS_TYPE + "=?",
new String[]{type});
ContentValues values = new ContentValues();
values.put(AUTHTOKENS_ACCOUNTS_ID, accountId);
values.put(AUTHTOKENS_TYPE, type);
values.put(AUTHTOKENS_AUTHTOKEN, authToken);
- if (db.insert(TABLE_AUTHTOKENS, AUTHTOKENS_AUTHTOKEN, values) >= 0) {
+ if (db.insert(CE_TABLE_AUTHTOKENS, AUTHTOKENS_AUTHTOKEN, values) >= 0) {
db.setTransactionSuccessful();
writeAuthTokenIntoCacheLocked(accounts, db, account, type, authToken);
return true;
@@ -1714,7 +1794,7 @@
return;
}
synchronized (accounts.cacheLock) {
- final SQLiteDatabase db = accounts.openHelper.getWritableDatabase();
+ final SQLiteDatabase db = accounts.openHelper.getWritableDatabaseUserIsUnlocked();
db.beginTransaction();
try {
final ContentValues values = new ContentValues();
@@ -1722,8 +1802,8 @@
final long accountId = getAccountIdLocked(db, account);
if (accountId >= 0) {
final String[] argsAccountId = {String.valueOf(accountId)};
- db.update(TABLE_ACCOUNTS, values, ACCOUNTS_ID + "=?", argsAccountId);
- db.delete(TABLE_AUTHTOKENS, AUTHTOKENS_ACCOUNTS_ID + "=?", argsAccountId);
+ db.update(CE_TABLE_ACCOUNTS, values, ACCOUNTS_ID + "=?", argsAccountId);
+ db.delete(CE_TABLE_AUTHTOKENS, AUTHTOKENS_ACCOUNTS_ID + "=?", argsAccountId);
accounts.authTokenCache.remove(account);
accounts.accountTokenCaches.remove(account);
db.setTransactionSuccessful();
@@ -1794,44 +1874,57 @@
long identityToken = clearCallingIdentity();
try {
UserAccounts accounts = getUserAccounts(userId);
- setUserdataInternal(accounts, account, key, value);
+ synchronized (accounts.cacheLock) {
+ if (!accountExistsCacheLocked(accounts, account)) {
+ return;
+ }
+ setUserdataInternalLocked(accounts, account, key, value);
+ }
} finally {
restoreCallingIdentity(identityToken);
}
}
- private void setUserdataInternal(UserAccounts accounts, Account account, String key,
+ private boolean accountExistsCacheLocked(UserAccounts accounts, Account account) {
+ if (accounts.accountCache.containsKey(account.type)) {
+ for (Account acc : accounts.accountCache.get(account.type)) {
+ if (acc.name.equals(account.name)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ private void setUserdataInternalLocked(UserAccounts accounts, Account account, String key,
String value) {
if (account == null || key == null) {
return;
}
- synchronized (accounts.cacheLock) {
- final SQLiteDatabase db = accounts.openHelper.getWritableDatabase();
- db.beginTransaction();
- try {
- long accountId = getAccountIdLocked(db, account);
- if (accountId < 0) {
+ final SQLiteDatabase db = accounts.openHelper.getWritableDatabase();
+ db.beginTransaction();
+ try {
+ long accountId = getAccountIdLocked(db, account);
+ if (accountId < 0) {
+ return;
+ }
+ long extrasId = getExtrasIdLocked(db, accountId, key);
+ if (extrasId < 0) {
+ extrasId = insertExtraLocked(db, accountId, key, value);
+ if (extrasId < 0) {
return;
}
- long extrasId = getExtrasIdLocked(db, accountId, key);
- if (extrasId < 0 ) {
- extrasId = insertExtraLocked(db, accountId, key, value);
- if (extrasId < 0) {
- return;
- }
- } else {
- ContentValues values = new ContentValues();
- values.put(EXTRAS_VALUE, value);
- if (1 != db.update(TABLE_EXTRAS, values, EXTRAS_ID + "=" + extrasId, null)) {
- return;
- }
-
+ } else {
+ ContentValues values = new ContentValues();
+ values.put(EXTRAS_VALUE, value);
+ if (1 != db.update(TABLE_EXTRAS, values, EXTRAS_ID + "=" + extrasId, null)) {
+ return;
}
- writeUserDataIntoCacheLocked(accounts, db, account, key, value);
- db.setTransactionSuccessful();
- } finally {
- db.endTransaction();
}
+ writeUserDataIntoCacheLocked(accounts, db, account, key, value);
+ db.setTransactionSuccessful();
+ } finally {
+ db.endTransaction();
}
}
@@ -2425,21 +2518,31 @@
userId);
return;
}
-
final int pid = Binder.getCallingPid();
final Bundle options = (optionsIn == null) ? new Bundle() : optionsIn;
options.putInt(AccountManager.KEY_CALLER_UID, uid);
options.putInt(AccountManager.KEY_CALLER_PID, pid);
+ // Check to see if the Password should be included to the caller.
+ String callerPkg = optionsIn.getString(AccountManager.KEY_ANDROID_PACKAGE_NAME);
+ boolean isPasswordForwardingAllowed = isPermitted(
+ callerPkg, uid, Manifest.permission.GET_PASSWORD_PRIVILEGED);
+
int usrId = UserHandle.getCallingUserId();
long identityToken = clearCallingIdentity();
try {
UserAccounts accounts = getUserAccounts(usrId);
logRecordWithUid(accounts, DebugDbHelper.ACTION_CALLED_START_ACCOUNT_ADD,
TABLE_ACCOUNTS, uid);
- new StartAccountSession(accounts, response, accountType, expectActivityLaunch,
- null /* accountName */, false /* authDetailsRequired */,
- true /* updateLastAuthenticationTime */) {
+ new StartAccountSession(
+ accounts,
+ response,
+ accountType,
+ expectActivityLaunch,
+ null /* accountName */,
+ false /* authDetailsRequired */,
+ true /* updateLastAuthenticationTime */,
+ isPasswordForwardingAllowed) {
@Override
public void run() throws RemoteException {
mAuthenticator.startAddAccountSession(this, mAccountType, authTokenType,
@@ -2462,12 +2565,21 @@
/** Session that will encrypt the KEY_ACCOUNT_SESSION_BUNDLE in result. */
private abstract class StartAccountSession extends Session {
- public StartAccountSession(UserAccounts accounts, IAccountManagerResponse response,
- String accountType, boolean expectActivityLaunch, String accountName,
- boolean authDetailsRequired, boolean updateLastAuthenticationTime) {
+ private final boolean mIsPasswordForwardingAllowed;
+
+ public StartAccountSession(
+ UserAccounts accounts,
+ IAccountManagerResponse response,
+ String accountType,
+ boolean expectActivityLaunch,
+ String accountName,
+ boolean authDetailsRequired,
+ boolean updateLastAuthenticationTime,
+ boolean isPasswordForwardingAllowed) {
super(accounts, response, accountType, expectActivityLaunch,
true /* stripAuthTokenFromResult */, accountName, authDetailsRequired,
updateLastAuthenticationTime);
+ mIsPasswordForwardingAllowed = isPasswordForwardingAllowed;
}
@Override
@@ -2480,6 +2592,10 @@
checkKeyIntent(
Binder.getCallingUid(),
intent);
+ // Omit passwords if the caller isn't permitted to see them.
+ if (!mIsPasswordForwardingAllowed) {
+ result.remove(AccountManager.KEY_PASSWORD);
+ }
}
IAccountManagerResponse response;
if (mExpectActivityLaunch && result != null
@@ -2826,6 +2942,12 @@
}
int userId = UserHandle.getCallingUserId();
+
+ // Check to see if the Password should be included to the caller.
+ String callerPkg = loginOptions.getString(AccountManager.KEY_ANDROID_PACKAGE_NAME);
+ boolean isPasswordForwardingAllowed = isPermitted(
+ callerPkg, uid, Manifest.permission.GET_PASSWORD_PRIVILEGED);
+
long identityToken = clearCallingIdentity();
try {
UserAccounts accounts = getUserAccounts(userId);
@@ -2836,7 +2958,8 @@
expectActivityLaunch,
account.name,
false /* authDetailsRequired */,
- true /* updateLastCredentialTime */) {
+ true /* updateLastCredentialTime */,
+ isPasswordForwardingAllowed) {
@Override
public void run() throws RemoteException {
mAuthenticator.startUpdateCredentialsSession(this, account, authTokenType,
@@ -3307,7 +3430,6 @@
long sharedTableAccountId = getAccountIdFromSharedTable(db, account);
final ContentValues values = new ContentValues();
values.put(ACCOUNTS_NAME, newName);
- values.put(ACCOUNTS_PREVIOUS_NAME, account.name);
int r = db.update(
TABLE_SHARED_ACCOUNTS,
values,
@@ -3347,7 +3469,7 @@
public Account[] getSharedAccountsAsUser(int userId) {
userId = handleIncomingUser(userId);
UserAccounts accounts = getUserAccounts(userId);
- ArrayList<Account> accountList = new ArrayList<Account>();
+ ArrayList<Account> accountList = new ArrayList<>();
Cursor cursor = null;
try {
cursor = accounts.openHelper.getReadableDatabase()
@@ -3488,7 +3610,7 @@
}
private long getExtrasIdLocked(SQLiteDatabase db, long accountId, String key) {
- Cursor cursor = db.query(TABLE_EXTRAS, new String[]{EXTRAS_ID},
+ Cursor cursor = db.query(CE_TABLE_EXTRAS, new String[]{EXTRAS_ID},
EXTRAS_ACCOUNTS_ID + "=" + accountId + " AND " + EXTRAS_KEY + "=?",
new String[]{key}, null, null, null);
try {
@@ -3729,8 +3851,8 @@
if (accountPresent) {
lastAuthenticatedTime = DatabaseUtils.longForQuery(
mAccounts.openHelper.getReadableDatabase(),
- "select " + ACCOUNTS_LAST_AUTHENTICATE_TIME_EPOCH_MILLIS
- + " from " +
+ "SELECT " + ACCOUNTS_LAST_AUTHENTICATE_TIME_EPOCH_MILLIS
+ + " FROM " +
TABLE_ACCOUNTS + " WHERE " + ACCOUNTS_NAME + "=? AND "
+ ACCOUNTS_TYPE + "=?",
new String[] {
@@ -3859,7 +3981,7 @@
Log.v(TAG, "performing bindService to " + authenticatorInfo.componentName);
}
if (!mContext.bindServiceAsUser(intent, this, Context.BIND_AUTO_CREATE,
- new UserHandle(mAccounts.userId))) {
+ UserHandle.of(mAccounts.userId))) {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "bindService to " + authenticatorInfo.componentName + " failed");
}
@@ -3893,15 +4015,16 @@
}
}
- private static String getDatabaseName(int userId) {
+ static String getPreNDatabaseName(int userId) {
File systemDir = Environment.getDataSystemDirectory();
- File databaseFile = new File(Environment.getUserSystemDirectory(userId), DATABASE_NAME);
+ File databaseFile = new File(Environment.getUserSystemDirectory(userId),
+ PRE_N_DATABASE_NAME);
if (userId == 0) {
// Migrate old file, if it exists, to the new location.
// Make sure the new file doesn't already exist. A dummy file could have been
// accidentally created in the old location, causing the new one to become corrupted
// as well.
- File oldFile = new File(systemDir, DATABASE_NAME);
+ File oldFile = new File(systemDir, PRE_N_DATABASE_NAME);
if (oldFile.exists() && !databaseFile.exists()) {
// Check for use directory; create if it doesn't exist, else renameTo will fail
File userDir = Environment.getUserSystemDirectory(userId);
@@ -3918,6 +4041,18 @@
return databaseFile.getPath();
}
+ static String getDeDatabaseName(int userId) {
+ File databaseFile = new File(Environment.getDataSystemDeDirectory(userId),
+ DE_DATABASE_NAME);
+ return databaseFile.getPath();
+ }
+
+ static String getCeDatabaseName(int userId) {
+ File databaseFile = new File(Environment.getDataSystemCeDirectory(userId),
+ CE_DATABASE_NAME);
+ return databaseFile.getPath();
+ }
+
private static class DebugDbHelper{
private DebugDbHelper() {
}
@@ -4050,58 +4185,22 @@
return DatabaseUtils.longForQuery(db, queryCountDebugDbRows, null);
}
- static class DatabaseHelper extends SQLiteOpenHelper {
+ static class PreNDatabaseHelper extends SQLiteOpenHelper {
private final Context mContext;
private final int mUserId;
- public DatabaseHelper(Context context, int userId) {
- super(context, AccountManagerService.getDatabaseName(userId), null, DATABASE_VERSION);
+ public PreNDatabaseHelper(Context context, int userId) {
+ super(context, AccountManagerService.getPreNDatabaseName(userId), null,
+ PRE_N_DATABASE_VERSION);
mContext = context;
mUserId = userId;
}
- /**
- * This call needs to be made while the mCacheLock is held. The way to
- * ensure this is to get the lock any time a method is called ont the DatabaseHelper
- * @param db The database.
- */
@Override
public void onCreate(SQLiteDatabase db) {
- db.execSQL("CREATE TABLE " + TABLE_ACCOUNTS + " ( "
- + ACCOUNTS_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, "
- + ACCOUNTS_NAME + " TEXT NOT NULL, "
- + ACCOUNTS_TYPE + " TEXT NOT NULL, "
- + ACCOUNTS_PASSWORD + " TEXT, "
- + ACCOUNTS_PREVIOUS_NAME + " TEXT, "
- + ACCOUNTS_LAST_AUTHENTICATE_TIME_EPOCH_MILLIS + " INTEGER DEFAULT 0, "
- + "UNIQUE(" + ACCOUNTS_NAME + "," + ACCOUNTS_TYPE + "))");
-
- db.execSQL("CREATE TABLE " + TABLE_AUTHTOKENS + " ( "
- + AUTHTOKENS_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, "
- + AUTHTOKENS_ACCOUNTS_ID + " INTEGER NOT NULL, "
- + AUTHTOKENS_TYPE + " TEXT NOT NULL, "
- + AUTHTOKENS_AUTHTOKEN + " TEXT, "
- + "UNIQUE (" + AUTHTOKENS_ACCOUNTS_ID + "," + AUTHTOKENS_TYPE + "))");
-
- createGrantsTable(db);
-
- db.execSQL("CREATE TABLE " + TABLE_EXTRAS + " ( "
- + EXTRAS_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, "
- + EXTRAS_ACCOUNTS_ID + " INTEGER, "
- + EXTRAS_KEY + " TEXT NOT NULL, "
- + EXTRAS_VALUE + " TEXT, "
- + "UNIQUE(" + EXTRAS_ACCOUNTS_ID + "," + EXTRAS_KEY + "))");
-
- db.execSQL("CREATE TABLE " + TABLE_META + " ( "
- + META_KEY + " TEXT PRIMARY KEY NOT NULL, "
- + META_VALUE + " TEXT)");
-
- createSharedAccountsTable(db);
-
- createAccountsDeletionTrigger(db);
-
- DebugDbHelper.createDebugTable(db);
+ // We use PreNDatabaseHelper only if pre-N db exists
+ throw new IllegalStateException("Legacy database cannot be created - only upgraded!");
}
private void createSharedAccountsTable(SQLiteDatabase db) {
@@ -4161,6 +4260,9 @@
}
}
+ /**
+ * Pre-N database may need an upgrade before splitting
+ */
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
Log.e(TAG, "upgrade from version " + oldVersion + " to version " + newVersion);
@@ -4222,6 +4324,315 @@
}
}
+ static class DeDatabaseHelper extends SQLiteOpenHelper {
+
+ private final int mUserId;
+ private volatile boolean mCeAttached;
+
+ private DeDatabaseHelper(Context context, int userId) {
+ super(context, getDeDatabaseName(userId), null, DE_DATABASE_VERSION);
+ mUserId = userId;
+ }
+
+ /**
+ * This call needs to be made while the mCacheLock is held. The way to
+ * ensure this is to get the lock any time a method is called ont the DatabaseHelper
+ * @param db The database.
+ */
+ @Override
+ public void onCreate(SQLiteDatabase db) {
+ Log.i(TAG, "Creating DE database for user " + mUserId);
+ db.execSQL("CREATE TABLE " + TABLE_ACCOUNTS + " ( "
+ + ACCOUNTS_ID + " INTEGER PRIMARY KEY, "
+ + ACCOUNTS_NAME + " TEXT NOT NULL, "
+ + ACCOUNTS_TYPE + " TEXT NOT NULL, "
+ + ACCOUNTS_PREVIOUS_NAME + " TEXT, "
+ + ACCOUNTS_LAST_AUTHENTICATE_TIME_EPOCH_MILLIS + " INTEGER DEFAULT 0, "
+ + "UNIQUE(" + ACCOUNTS_NAME + "," + ACCOUNTS_TYPE + "))");
+
+ db.execSQL("CREATE TABLE " + TABLE_META + " ( "
+ + META_KEY + " TEXT PRIMARY KEY NOT NULL, "
+ + META_VALUE + " TEXT)");
+
+ createGrantsTable(db);
+ createSharedAccountsTable(db);
+ createAccountsDeletionTrigger(db);
+ DebugDbHelper.createDebugTable(db);
+ }
+
+ private void createSharedAccountsTable(SQLiteDatabase db) {
+ db.execSQL("CREATE TABLE " + TABLE_SHARED_ACCOUNTS + " ( "
+ + ACCOUNTS_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, "
+ + ACCOUNTS_NAME + " TEXT NOT NULL, "
+ + ACCOUNTS_TYPE + " TEXT NOT NULL, "
+ + "UNIQUE(" + ACCOUNTS_NAME + "," + ACCOUNTS_TYPE + "))");
+ }
+
+ private void createAccountsDeletionTrigger(SQLiteDatabase db) {
+ db.execSQL(""
+ + " CREATE TRIGGER " + TABLE_ACCOUNTS + "Delete DELETE ON " + TABLE_ACCOUNTS
+ + " BEGIN"
+ + " DELETE FROM " + TABLE_GRANTS
+ + " WHERE " + GRANTS_ACCOUNTS_ID + "=OLD." + ACCOUNTS_ID + " ;"
+ + " END");
+ }
+
+ private void createGrantsTable(SQLiteDatabase db) {
+ db.execSQL("CREATE TABLE " + TABLE_GRANTS + " ( "
+ + GRANTS_ACCOUNTS_ID + " INTEGER NOT NULL, "
+ + GRANTS_AUTH_TOKEN_TYPE + " STRING NOT NULL, "
+ + GRANTS_GRANTEE_UID + " INTEGER NOT NULL, "
+ + "UNIQUE (" + GRANTS_ACCOUNTS_ID + "," + GRANTS_AUTH_TOKEN_TYPE
+ + "," + GRANTS_GRANTEE_UID + "))");
+ }
+
+ @Override
+ public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
+ Log.i(TAG, "upgrade from version " + oldVersion + " to version " + newVersion);
+
+ if (oldVersion != newVersion) {
+ Log.e(TAG, "failed to upgrade version " + oldVersion + " to version " + newVersion);
+ }
+ }
+
+ public void attachCeDatabase() {
+ File ceDbFile = new File(getCeDatabaseName(mUserId));
+ SQLiteDatabase db = getWritableDatabase();
+ db.execSQL("ATTACH DATABASE '" + ceDbFile.getPath()+ "' AS ceDb");
+ mCeAttached = true;
+ }
+
+ public boolean isCeDatabaseAttached() {
+ return mCeAttached;
+ }
+
+
+ public SQLiteDatabase getReadableDatabaseUserIsUnlocked() {
+ if(!mCeAttached) {
+ Log.wtf(TAG, "getReadableDatabaseUserIsUnlocked called while user "
+ + mUserId + " is still locked ", new Throwable());
+ }
+ return super.getReadableDatabase();
+ }
+
+ public SQLiteDatabase getWritableDatabaseUserIsUnlocked() {
+ if(!mCeAttached) {
+ Log.wtf(TAG, "getWritableDatabaseUserIsUnlocked called while user " + mUserId
+ + " is still locked ", new Throwable());
+ }
+ return super.getWritableDatabase();
+ }
+
+ @Override
+ public void onOpen(SQLiteDatabase db) {
+ if (Log.isLoggable(TAG, Log.VERBOSE)) Log.v(TAG, "opened database " + DE_DATABASE_NAME);
+ }
+
+ private void migratePreNDbToDe(File preNDbFile) {
+ Log.i(TAG, "Migrate pre-N database to DE preNDbFile=" + preNDbFile);
+ SQLiteDatabase db = getWritableDatabase();
+ db.execSQL("ATTACH DATABASE '" + preNDbFile.getPath() + "' AS preNDb");
+ db.beginTransaction();
+ // Copy accounts fields
+ db.execSQL("INSERT INTO " + TABLE_ACCOUNTS
+ + "(" + ACCOUNTS_ID + "," + ACCOUNTS_NAME + "," + ACCOUNTS_TYPE + ", "
+ + ACCOUNTS_PREVIOUS_NAME + ", " + ACCOUNTS_LAST_AUTHENTICATE_TIME_EPOCH_MILLIS
+ + ") "
+ + "SELECT " + ACCOUNTS_ID + "," + ACCOUNTS_NAME + "," + ACCOUNTS_TYPE + ", "
+ + ACCOUNTS_PREVIOUS_NAME + ", " + ACCOUNTS_LAST_AUTHENTICATE_TIME_EPOCH_MILLIS
+ + " FROM preNDb." + TABLE_ACCOUNTS);
+ // Copy SHARED_ACCOUNTS
+ db.execSQL("INSERT INTO " + TABLE_SHARED_ACCOUNTS
+ + "(" + SHARED_ACCOUNTS_ID + "," + ACCOUNTS_NAME + "," + ACCOUNTS_TYPE + ") " +
+ "SELECT " + SHARED_ACCOUNTS_ID + "," + ACCOUNTS_NAME + "," + ACCOUNTS_TYPE
+ + " FROM preNDb." + TABLE_SHARED_ACCOUNTS);
+ // Copy DEBUG_TABLE
+ db.execSQL("INSERT INTO " + DebugDbHelper.TABLE_DEBUG
+ + "(" + ACCOUNTS_ID + "," + DebugDbHelper.ACTION_TYPE + ","
+ + DebugDbHelper.TIMESTAMP + "," + DebugDbHelper.CALLER_UID + ","
+ + DebugDbHelper.TABLE_NAME + "," + DebugDbHelper.KEY + ") " +
+ "SELECT " + ACCOUNTS_ID + "," + DebugDbHelper.ACTION_TYPE + ","
+ + DebugDbHelper.TIMESTAMP + "," + DebugDbHelper.CALLER_UID + ","
+ + DebugDbHelper.TABLE_NAME + "," + DebugDbHelper.KEY
+ + " FROM preNDb." + DebugDbHelper.TABLE_DEBUG);
+ // Copy GRANTS
+ db.execSQL("INSERT INTO " + TABLE_GRANTS
+ + "(" + GRANTS_ACCOUNTS_ID + "," + GRANTS_AUTH_TOKEN_TYPE + ","
+ + GRANTS_GRANTEE_UID + ") " +
+ "SELECT " + GRANTS_ACCOUNTS_ID + "," + GRANTS_AUTH_TOKEN_TYPE + ","
+ + GRANTS_GRANTEE_UID + " FROM preNDb." + TABLE_GRANTS);
+ // Copy META
+ db.execSQL("INSERT INTO " + TABLE_META
+ + "(" + META_KEY + "," + META_VALUE + ") "
+ + "SELECT " + META_KEY + "," + META_VALUE + " FROM preNDb." + TABLE_META);
+ db.setTransactionSuccessful();
+ db.endTransaction();
+
+ db.execSQL("DETACH DATABASE preNDb");
+ }
+
+ static DeDatabaseHelper create(Context context, int userId) {
+ File oldDb = new File(getPreNDatabaseName(userId));
+ File newDb = new File(getDeDatabaseName(userId));
+ boolean newDbExists = newDb.exists();
+ DeDatabaseHelper deDatabaseHelper = new DeDatabaseHelper(context, userId);
+ // If the db just created, and there is a legacy db, migrate it
+ if (!newDbExists && oldDb.exists()) {
+ // Migrate legacy db to the latest version - PRE_N_DATABASE_VERSION
+ PreNDatabaseHelper preNDatabaseHelper = new PreNDatabaseHelper(context, userId);
+ // Open the database to force upgrade if required
+ preNDatabaseHelper.getWritableDatabase();
+ preNDatabaseHelper.close();
+ // Move data without SPII to DE
+ deDatabaseHelper.migratePreNDbToDe(oldDb);
+ }
+ return deDatabaseHelper;
+ }
+ }
+
+ static class CeDatabaseHelper extends SQLiteOpenHelper {
+
+ public CeDatabaseHelper(Context context, int userId) {
+ super(context, getCeDatabaseName(userId), null, CE_DATABASE_VERSION);
+ }
+
+ /**
+ * This call needs to be made while the mCacheLock is held.
+ * @param db The database.
+ */
+ @Override
+ public void onCreate(SQLiteDatabase db) {
+ Log.i(TAG, "Creating CE database " + getDatabaseName());
+ db.execSQL("CREATE TABLE " + TABLE_ACCOUNTS + " ( "
+ + ACCOUNTS_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, "
+ + ACCOUNTS_NAME + " TEXT NOT NULL, "
+ + ACCOUNTS_TYPE + " TEXT NOT NULL, "
+ + ACCOUNTS_PASSWORD + " TEXT, "
+ + "UNIQUE(" + ACCOUNTS_NAME + "," + ACCOUNTS_TYPE + "))");
+
+ db.execSQL("CREATE TABLE " + TABLE_AUTHTOKENS + " ( "
+ + AUTHTOKENS_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, "
+ + AUTHTOKENS_ACCOUNTS_ID + " INTEGER NOT NULL, "
+ + AUTHTOKENS_TYPE + " TEXT NOT NULL, "
+ + AUTHTOKENS_AUTHTOKEN + " TEXT, "
+ + "UNIQUE (" + AUTHTOKENS_ACCOUNTS_ID + "," + AUTHTOKENS_TYPE + "))");
+
+ db.execSQL("CREATE TABLE " + TABLE_EXTRAS + " ( "
+ + EXTRAS_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, "
+ + EXTRAS_ACCOUNTS_ID + " INTEGER, "
+ + EXTRAS_KEY + " TEXT NOT NULL, "
+ + EXTRAS_VALUE + " TEXT, "
+ + "UNIQUE(" + EXTRAS_ACCOUNTS_ID + "," + EXTRAS_KEY + "))");
+
+ createAccountsDeletionTrigger(db);
+ }
+
+ private void createAccountsDeletionTrigger(SQLiteDatabase db) {
+ db.execSQL(""
+ + " CREATE TRIGGER " + TABLE_ACCOUNTS + "Delete DELETE ON " + TABLE_ACCOUNTS
+ + " BEGIN"
+ + " DELETE FROM " + TABLE_AUTHTOKENS
+ + " WHERE " + AUTHTOKENS_ACCOUNTS_ID + "=OLD." + ACCOUNTS_ID + " ;"
+ + " DELETE FROM " + TABLE_EXTRAS
+ + " WHERE " + EXTRAS_ACCOUNTS_ID + "=OLD." + ACCOUNTS_ID + " ;"
+ + " END");
+ }
+
+ @Override
+ public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
+ Log.i(TAG, "Upgrade CE from version " + oldVersion + " to version " + newVersion);
+
+ if (oldVersion == 9) {
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG, "onUpgrade upgrading to v10");
+ }
+ db.execSQL("DROP TABLE IF EXISTS " + TABLE_META);
+ db.execSQL("DROP TABLE IF EXISTS " + TABLE_SHARED_ACCOUNTS);
+ // Recreate the trigger, since the old one references the table to be removed
+ db.execSQL("DROP TRIGGER IF EXISTS " + TABLE_ACCOUNTS + "Delete");
+ createAccountsDeletionTrigger(db);
+ db.execSQL("DROP TABLE IF EXISTS " + TABLE_GRANTS);
+ db.execSQL("DROP TABLE IF EXISTS " + DebugDbHelper.TABLE_DEBUG);
+ oldVersion ++;
+ }
+
+ if (oldVersion != newVersion) {
+ Log.e(TAG, "failed to upgrade version " + oldVersion + " to version " + newVersion);
+ }
+ }
+
+ @Override
+ public void onOpen(SQLiteDatabase db) {
+ if (Log.isLoggable(TAG, Log.VERBOSE)) Log.v(TAG, "opened database " + CE_DATABASE_NAME);
+ }
+
+ static String findAccountPasswordByNameAndType(SQLiteDatabase db, String name,
+ String type) {
+ Cursor cursor = db.query(CE_TABLE_ACCOUNTS, new String[]{ACCOUNTS_PASSWORD},
+ ACCOUNTS_NAME + "=? AND " + ACCOUNTS_TYPE + "=?",
+ new String[]{name, type}, null, null, null);
+ try {
+ if (cursor.moveToNext()) {
+ return cursor.getString(0);
+ }
+ return null;
+ } finally {
+ cursor.close();
+ }
+ }
+
+ /**
+ * Creates a new {@code CeDatabaseHelper}. If pre-N db file is present at the old location,
+ * it also performs migration to the new CE database.
+ * @param context
+ * @param userId id of the user where the database is located
+ */
+ static CeDatabaseHelper create(Context context, int userId) {
+
+ File oldDatabaseFile = new File(getPreNDatabaseName(userId));
+ File ceDatabaseFile = new File(getCeDatabaseName(userId));
+ boolean newDbExists = ceDatabaseFile.exists();
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG, "CeDatabaseHelper.create userId=" + userId + " oldDbExists="
+ + oldDatabaseFile.exists() + " newDbExists=" + newDbExists);
+ }
+ boolean removeOldDb = false;
+ if (!newDbExists && oldDatabaseFile.exists()) {
+ removeOldDb = migratePreNDbToCe(oldDatabaseFile, ceDatabaseFile);
+ }
+ // Try to open and upgrade if necessary
+ CeDatabaseHelper ceHelper = new CeDatabaseHelper(context, userId);
+ ceHelper.getWritableDatabase();
+ ceHelper.close();
+ if (removeOldDb) {
+ // TODO STOPSHIP - backup file during testing. Remove file before the release
+ Log.i(TAG, "Migration complete - creating backup of old db " + oldDatabaseFile);
+ renameToBakFile(oldDatabaseFile);
+ }
+ return ceHelper;
+ }
+
+ private static void renameToBakFile(File file) {
+ File bakFile = new File(file.getPath() + ".bak");
+ if (!file.renameTo(bakFile)) {
+ Log.e(TAG, "Cannot move file to " + bakFile);
+ }
+ }
+
+ private static boolean migratePreNDbToCe(File oldDbFile, File ceDbFile) {
+ Log.i(TAG, "Moving pre-N DB " + oldDbFile + " to CE " + ceDbFile);
+ try {
+ FileUtils.copyFileOrThrow(oldDbFile, ceDbFile);
+ } catch (IOException e) {
+ Log.e(TAG, "Cannot copy file to " + ceDbFile + " from " + oldDbFile, e);
+ // Try to remove potentially damaged file if I/O error occurred
+ deleteDbFileWarnIfFailed(ceDbFile);
+ return false;
+ }
+ return true;
+ }
+ }
+
public IBinder onBind(@SuppressWarnings("unused") Intent intent) {
return asBinder();
}
@@ -4666,7 +5077,7 @@
db.endTransaction();
}
cancelNotification(getCredentialPermissionNotificationId(account, authTokenType, uid),
- new UserHandle(accounts.userId));
+ UserHandle.of(accounts.userId));
}
}
@@ -4891,7 +5302,7 @@
HashMap<String, String> authTokensForAccount = accounts.authTokenCache.get(account);
if (authTokensForAccount == null) {
// need to populate the cache for this account
- final SQLiteDatabase db = accounts.openHelper.getReadableDatabase();
+ final SQLiteDatabase db = accounts.openHelper.getReadableDatabaseUserIsUnlocked();
authTokensForAccount = readAuthTokensForAccountFromDatabaseLocked(db, account);
accounts.authTokenCache.put(account, authTokensForAccount);
}
@@ -4899,23 +5310,22 @@
}
}
- protected String readUserDataInternal(UserAccounts accounts, Account account, String key) {
- synchronized (accounts.cacheLock) {
- HashMap<String, String> userDataForAccount = accounts.userDataCache.get(account);
- if (userDataForAccount == null) {
- // need to populate the cache for this account
- final SQLiteDatabase db = accounts.openHelper.getReadableDatabase();
- userDataForAccount = readUserDataForAccountFromDatabaseLocked(db, account);
- accounts.userDataCache.put(account, userDataForAccount);
- }
- return userDataForAccount.get(key);
+ protected String readUserDataInternalLocked(
+ UserAccounts accounts, Account account, String key) {
+ HashMap<String, String> userDataForAccount = accounts.userDataCache.get(account);
+ if (userDataForAccount == null) {
+ // need to populate the cache for this account
+ final SQLiteDatabase db = accounts.openHelper.getReadableDatabase();
+ userDataForAccount = readUserDataForAccountFromDatabaseLocked(db, account);
+ accounts.userDataCache.put(account, userDataForAccount);
}
+ return userDataForAccount.get(key);
}
protected HashMap<String, String> readUserDataForAccountFromDatabaseLocked(
final SQLiteDatabase db, Account account) {
- HashMap<String, String> userDataForAccount = new HashMap<String, String>();
- Cursor cursor = db.query(TABLE_EXTRAS,
+ HashMap<String, String> userDataForAccount = new HashMap<>();
+ Cursor cursor = db.query(CE_TABLE_EXTRAS,
COLUMNS_EXTRAS_KEY_AND_VALUE,
SELECTION_USERDATA_BY_ACCOUNT,
new String[]{account.name, account.type},
@@ -4934,8 +5344,8 @@
protected HashMap<String, String> readAuthTokensForAccountFromDatabaseLocked(
final SQLiteDatabase db, Account account) {
- HashMap<String, String> authTokensForAccount = new HashMap<String, String>();
- Cursor cursor = db.query(TABLE_AUTHTOKENS,
+ HashMap<String, String> authTokensForAccount = new HashMap<>();
+ Cursor cursor = db.query(CE_TABLE_AUTHTOKENS,
COLUMNS_AUTHTOKENS_TYPE_AND_AUTHTOKEN,
SELECTION_AUTHTOKENS_BY_ACCOUNT,
new String[]{account.name, account.type},
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index f51fb6c..5d1cb8a 100755
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -43,7 +43,8 @@
import android.util.ArrayMap;
import android.util.ArraySet;
-import com.android.internal.app.ProcessStats;
+import com.android.internal.app.procstats.ProcessStats;
+import com.android.internal.app.procstats.ServiceState;
import com.android.internal.os.BatteryStatsImpl;
import com.android.internal.os.TransferPipe;
import com.android.internal.util.FastPrintWriter;
@@ -61,7 +62,6 @@
import android.content.Context;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
@@ -343,6 +343,25 @@
return null;
}
+ if (!r.startRequested) {
+ final long token = Binder.clearCallingIdentity();
+ try {
+ // Before going further -- if this app is not allowed to run in the
+ // background, then at this point we aren't going to let it period.
+ final int allowed = mAm.checkAllowBackgroundLocked(
+ r.appInfo.uid, r.packageName, callingPid, true);
+ if (allowed != ActivityManager.APP_START_MODE_NORMAL) {
+ Slog.w(TAG, "Background start not allowed: service "
+ + service + " to " + r.name.flattenToShortString()
+ + " from pid=" + callingPid + " uid=" + callingUid
+ + " pkg=" + callingPackage);
+ return null;
+ }
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
NeededUriGrants neededGrants = mAm.checkGrantUriPermissionFromIntentLocked(
callingUid, r.packageName, service, service.getFlags(), null, r.userId);
@@ -480,7 +499,7 @@
ComponentName startServiceInnerLocked(ServiceMap smap, Intent service, ServiceRecord r,
boolean callerFg, boolean addToStarting) throws TransactionTooLargeException {
- ProcessStats.ServiceState stracker = r.getTracker();
+ ServiceState stracker = r.getTracker();
if (stracker != null) {
stracker.setStarted(true, mAm.mProcessStats.getMemFactorLocked(), r.lastActivity);
}
@@ -932,7 +951,7 @@
s.lastActivity = SystemClock.uptimeMillis();
if (!s.hasAutoCreateConnections()) {
// This is the first binding, let the tracker know.
- ProcessStats.ServiceState stracker = s.getTracker();
+ ServiceState stracker = s.getTracker();
if (stracker != null) {
stracker.setBound(true, mAm.mProcessStats.getMemFactorLocked(),
s.lastActivity);
@@ -940,7 +959,7 @@
}
}
- mAm.startAssociationLocked(callerApp.uid, callerApp.processName,
+ mAm.startAssociationLocked(callerApp.uid, callerApp.processName, callerApp.curProcState,
s.appInfo.uid, s.name, s.processName);
AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp);
@@ -1274,23 +1293,6 @@
}
r = smap.mServicesByName.get(name);
if (r == null && createIfNeeded) {
- final long token = Binder.clearCallingIdentity();
- try {
- // Before going further -- if this app is not allowed to run in the
- // background, then at this point we aren't going to let it period.
- final int allowed = mAm.checkAllowBackgroundLocked(
- sInfo.applicationInfo.uid, sInfo.packageName, callingPid);
- if (allowed != ActivityManager.APP_START_MODE_NORMAL) {
- Slog.w(TAG, "Background execution not allowed: service "
- + service + " to " + name.flattenToShortString()
- + " from pid=" + callingPid + " uid=" + callingUid
- + " pkg=" + callingPackage);
- return null;
- }
- } finally {
- Binder.restoreCallingIdentity(token);
- }
-
Intent.FilterComparison filter
= new Intent.FilterComparison(service.cloneFilter());
ServiceRestarter res = new ServiceRestarter();
@@ -1365,7 +1367,7 @@
long now = SystemClock.uptimeMillis();
if (r.executeNesting == 0) {
r.executeFg = fg;
- ProcessStats.ServiceState stracker = r.getTracker();
+ ServiceState stracker = r.getTracker();
if (stracker != null) {
stracker.setExecuting(true, mAm.mProcessStats.getMemFactorLocked(), now);
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 8b67d0e..1da6a20 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -26,8 +26,8 @@
import com.android.internal.app.IAppOpsService;
import com.android.internal.app.IVoiceInteractor;
import com.android.internal.app.ProcessMap;
-import com.android.internal.app.ProcessStats;
import com.android.internal.app.SystemUserHomeActivity;
+import com.android.internal.app.procstats.ProcessStats;
import com.android.internal.os.BackgroundThread;
import com.android.internal.os.BatteryStatsImpl;
import com.android.internal.os.IResultReceiver;
@@ -351,7 +351,6 @@
import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_PINNABLE;
import static com.android.server.wm.AppTransition.TRANSIT_ACTIVITY_OPEN;
import static com.android.server.wm.AppTransition.TRANSIT_ACTIVITY_RELAUNCH;
-import static com.android.server.wm.AppTransition.TRANSIT_DOCK_TASK_FROM_RECENTS;
import static com.android.server.wm.AppTransition.TRANSIT_TASK_IN_PLACE;
import static com.android.server.wm.AppTransition.TRANSIT_TASK_OPEN;
import static com.android.server.wm.AppTransition.TRANSIT_TASK_TO_FRONT;
@@ -892,6 +891,12 @@
int mNesting;
long mStartTime;
+ // states of the source process when the bind occurred.
+ int mLastState = ActivityManager.MAX_PROCESS_STATE + 1;
+ long mLastStateUptime;
+ long[] mStateTimes = new long[ActivityManager.MAX_PROCESS_STATE
+ - ActivityManager.MIN_PROCESS_STATE+1];
+
Association(int sourceUid, String sourceProcess, int targetUid,
ComponentName targetComponent, String targetProcess) {
mSourceUid = sourceUid;
@@ -1100,20 +1105,20 @@
ComponentName mTopComponent;
String mTopAction = Intent.ACTION_MAIN;
String mTopData;
- boolean mProcessesReady = false;
- boolean mSystemReady = false;
- boolean mBooting = false;
- boolean mCallFinishBooting = false;
- boolean mBootAnimationComplete = false;
- boolean mOnBattery = false;
- boolean mLaunchWarningShown = false;
+
+ volatile boolean mProcessesReady = false;
+ volatile boolean mSystemReady = false;
+ volatile boolean mOnBattery = false;
+ volatile int mFactoryTest;
+
+ @GuardedBy("this") boolean mBooting = false;
+ @GuardedBy("this") boolean mCallFinishBooting = false;
+ @GuardedBy("this") boolean mBootAnimationComplete = false;
+ @GuardedBy("this") boolean mLaunchWarningShown = false;
+ @GuardedBy("this") boolean mCheckedForSetup = false;
Context mContext;
- int mFactoryTest;
-
- boolean mCheckedForSetup;
-
/**
* The time at which we will allow normal application switches again,
* after a call to {@link #stopAppSwitches()}.
@@ -1468,6 +1473,9 @@
static final int FIRST_COMPAT_MODE_MSG = 300;
static final int FIRST_SUPERVISOR_STACK_MSG = 100;
+ static ServiceThread sKillThread = null;
+ static KillHandler sKillHandler = null;
+
CompatModeDialog mCompatModeDialog;
long mLastMemUsageReportTime = 0;
@@ -1488,10 +1496,33 @@
final ServiceThread mHandlerThread;
final MainHandler mHandler;
final UiHandler mUiHandler;
- final ProcessStartLogger mProcessStartLogger;
PackageManagerInternal mPackageManagerInt;
+ final class KillHandler extends Handler {
+ static final int KILL_PROCESS_GROUP_MSG = 4000;
+
+ public KillHandler(Looper looper) {
+ super(looper, null, true);
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case KILL_PROCESS_GROUP_MSG:
+ {
+ Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "killProcessGroup");
+ Process.killProcessGroup(msg.arg1 /* uid */, msg.arg2 /* pid */);
+ Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
+ }
+ break;
+
+ default:
+ super.handleMessage(msg);
+ }
+ }
+ }
+
final class UiHandler extends Handler {
public UiHandler() {
super(com.android.server.UiThread.get().getLooper(), null, true);
@@ -2460,7 +2491,13 @@
mHandler = new MainHandler(mHandlerThread.getLooper());
mUiHandler = new UiHandler();
- mProcessStartLogger = new ProcessStartLogger();
+ /* static; one-time init here */
+ if (sKillHandler == null) {
+ sKillThread = new ServiceThread(TAG + ":kill",
+ android.os.Process.THREAD_PRIORITY_BACKGROUND, true /* allowIo */);
+ sKillThread.start();
+ sKillHandler = new KillHandler(sKillThread.getLooper());
+ }
mFgBroadcastQueue = new BroadcastQueue(this, mHandler,
"foreground", BROADCAST_FG_TIMEOUT, false);
@@ -3010,9 +3047,13 @@
}
static void killProcessGroup(int uid, int pid) {
- Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "killProcessGroup");
- Process.killProcessGroup(uid, pid);
- Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
+ if (sKillHandler != null) {
+ sKillHandler.sendMessage(
+ sKillHandler.obtainMessage(KillHandler.KILL_PROCESS_GROUP_MSG, uid, pid));
+ } else {
+ Slog.w(TAG, "Asked to kill process group before system bringup!");
+ Process.killProcessGroup(uid, pid);
+ }
}
final void removeLruProcessLocked(ProcessRecord app) {
@@ -3594,7 +3635,12 @@
app.processName, hostingType,
hostingNameStr != null ? hostingNameStr : "");
- mProcessStartLogger.logIfNeededLocked(app, startResult);
+ try {
+ AppGlobals.getPackageManager().logAppProcessStartIfNeeded(app.processName, app.uid,
+ app.info.seinfo, app.info.sourceDir, startResult.pid);
+ } catch (RemoteException ex) {
+ // Ignore
+ }
if (app.persistent) {
Watchdog.getInstance().processStarted(app.processName, startResult.pid);
@@ -6016,8 +6062,7 @@
"No more processes in " + old.uidRecord);
enqueueUidChangeLocked(old.uidRecord, -1, UidRecord.CHANGE_GONE);
mActiveUids.remove(uid);
- mBatteryStatsService.noteUidProcessState(uid,
- ActivityManager.PROCESS_STATE_NONEXISTENT);
+ noteUidProcessState(uid, ActivityManager.PROCESS_STATE_NONEXISTENT);
}
old.uidRecord = null;
}
@@ -6042,7 +6087,7 @@
if (DEBUG_UID_OBSERVERS) Slog.i(TAG_UID_OBSERVERS,
"Creating new process uid: " + uidRec);
mActiveUids.put(proc.uid, uidRec);
- mBatteryStatsService.noteUidProcessState(uidRec.uid, uidRec.curProcState);
+ noteUidProcessState(uidRec.uid, uidRec.curProcState);
enqueueUidChangeLocked(uidRec, -1, UidRecord.CHANGE_ACTIVE);
}
proc.uidRecord = uidRec;
@@ -6537,8 +6582,6 @@
}
}, dumpheapFilter);
- mProcessStartLogger.registerListener(mContext);
-
// Let system services know.
mSystemServiceManager.startBootPhase(SystemService.PHASE_BOOT_COMPLETED);
@@ -7182,8 +7225,17 @@
}
}
+ // NOTE: this is an internal method used by the OnShellCommand implementation only and should
+ // be guarded by permission checking.
+ int getUidState(int uid) {
+ synchronized (this) {
+ UidRecord uidRec = mActiveUids.get(uid);
+ return uidRec == null ? ActivityManager.PROCESS_STATE_NONEXISTENT : uidRec.curProcState;
+ }
+ }
+
@Override
- public boolean inMultiWindow(IBinder token) {
+ public boolean isInMultiWindowMode(IBinder token) {
final long origId = Binder.clearCallingIdentity();
try {
synchronized(this) {
@@ -7200,7 +7252,7 @@
}
@Override
- public boolean inPictureInPicture(IBinder token) {
+ public boolean isInPictureInPictureMode(IBinder token) {
final long origId = Binder.clearCallingIdentity();
try {
synchronized(this) {
@@ -7216,24 +7268,24 @@
}
@Override
- public void enterPictureInPicture(IBinder token) {
+ public void enterPictureInPictureMode(IBinder token) {
final long origId = Binder.clearCallingIdentity();
try {
synchronized(this) {
if (!mSupportsPictureInPicture) {
- throw new IllegalStateException("enterPictureInPicture: "
+ throw new IllegalStateException("enterPictureInPictureMode: "
+ "Device doesn't support picture-in-picture mode.");
}
final ActivityRecord r = ActivityRecord.forTokenLocked(token);
if (r == null) {
- throw new IllegalStateException("enterPictureInPicture: "
+ throw new IllegalStateException("enterPictureInPictureMode: "
+ "Can't find activity for token=" + token);
}
if (!r.supportsPictureInPicture()) {
- throw new IllegalArgumentException("enterPictureInPicture: "
+ throw new IllegalArgumentException("enterPictureInPictureMode: "
+ "Picture-In-Picture not supported for r=" + r);
}
@@ -7242,7 +7294,7 @@
? mDefaultPinnedStackBounds : null;
mStackSupervisor.moveActivityToPinnedStackLocked(
- r, "enterPictureInPicture", bounds);
+ r, "enterPictureInPictureMode", bounds);
}
} finally {
Binder.restoreCallingIdentity(origId);
@@ -7535,14 +7587,15 @@
public int getAppStartMode(int uid, String packageName) {
synchronized (this) {
- return checkAllowBackgroundLocked(uid, packageName, -1);
+ return checkAllowBackgroundLocked(uid, packageName, -1, true);
}
}
- int checkAllowBackgroundLocked(int uid, String packageName, int callingPid) {
+ int checkAllowBackgroundLocked(int uid, String packageName, int callingPid,
+ boolean allowWhenForeground) {
UidRecord uidRec = mActiveUids.get(uid);
if (!mLenientBackgroundCheck) {
- if (uidRec == null
+ if (!allowWhenForeground || uidRec == null
|| uidRec.curProcState >= ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND) {
if (mAppOpsService.noteOperation(AppOpsManager.OP_RUN_IN_BACKGROUND, uid,
packageName) != AppOpsManager.MODE_ALLOWED) {
@@ -8845,10 +8898,11 @@
continue;
}
}
- if ((flags & ActivityManager.RECENT_INGORE_DOCKED_STACK_TASKS) != 0) {
- if (tr.stack != null && tr.stack.isDockedStack()) {
+ if ((flags & ActivityManager.RECENT_INGORE_DOCKED_STACK_TOP_TASK) != 0) {
+ final ActivityStack stack = tr.stack;
+ if (stack != null && stack.isDockedStack() && stack.topTask() == tr) {
if (DEBUG_RECENTS) Slog.d(TAG_RECENTS,
- "Skipping, docked stack task: " + tr);
+ "Skipping, top task in docked stack: " + tr);
continue;
}
}
@@ -9773,7 +9827,8 @@
public void updateLockTaskPackages(int userId, String[] packages) {
final int callingUid = Binder.getCallingUid();
if (callingUid != 0 && callingUid != Process.SYSTEM_UID) {
- throw new SecurityException("updateLockTaskPackage called from non-system process");
+ enforceCallingPermission(android.Manifest.permission.UPDATE_LOCK_TASK_PACKAGES,
+ "updateLockTaskPackages()");
}
synchronized (this) {
if (DEBUG_LOCKTASK) Slog.w(TAG_LOCKTASK, "Whitelisting " + userId + ":" +
@@ -10141,7 +10196,8 @@
}
cpr.connections.add(conn);
r.conProviders.add(conn);
- startAssociationLocked(r.uid, r.processName, cpr.uid, cpr.name, cpr.info.processName);
+ startAssociationLocked(r.uid, r.processName, r.curProcState,
+ cpr.uid, cpr.name, cpr.info.processName);
return conn;
}
cpr.addExternalProcessHandleLocked(externalProcessToken);
@@ -13203,6 +13259,7 @@
}
}
+ @Override
public List<ActivityManager.ProcessErrorStateInfo> getProcessesInErrorState() {
enforceNotIsolatedCaller("getProcessesInErrorState");
// assume our apps are happy - lazy create the list
@@ -13279,6 +13336,7 @@
outInfo.processState = app.curProcState;
}
+ @Override
public List<ActivityManager.RunningAppProcessInfo> getRunningAppProcesses() {
enforceNotIsolatedCaller("getRunningAppProcesses");
@@ -13330,6 +13388,7 @@
return runList;
}
+ @Override
public List<ApplicationInfo> getRunningExternalApplications() {
enforceNotIsolatedCaller("getRunningExternalApplications");
List<ActivityManager.RunningAppProcessInfo> runningApps = getRunningAppProcesses();
@@ -13745,10 +13804,27 @@
TimeUtils.formatDuration(dur, pw);
pw.print(" (");
pw.print(ass.mCount);
- pw.println(" times)");
+ pw.print(" times)");
+ pw.print(" ");
+ for (int i=0; i<ass.mStateTimes.length; i++) {
+ long amt = ass.mStateTimes[i];
+ if (ass.mLastState-ActivityManager.MIN_PROCESS_STATE == i) {
+ amt += now - ass.mLastStateUptime;
+ }
+ if (amt != 0) {
+ pw.print(" ");
+ pw.print(ProcessList.makeProcStateString(
+ i + ActivityManager.MIN_PROCESS_STATE));
+ pw.print("=");
+ TimeUtils.formatDuration(amt, pw);
+ if (ass.mLastState-ActivityManager.MIN_PROCESS_STATE == i) {
+ pw.print("*");
+ }
+ }
+ }
+ pw.println();
if (ass.mNesting > 0) {
- pw.print(" ");
- pw.print(" Currently active: ");
+ pw.print(" Currently active: ");
TimeUtils.formatDuration(now - ass.mStartTime, pw);
pw.println();
}
@@ -17969,6 +18045,9 @@
ActivityRecord starting, boolean initLocale, boolean persistent, int userId) {
int changes = 0;
+ if (mWindowManager != null) {
+ mWindowManager.deferSurfaceLayout();
+ }
if (values != null) {
Configuration newConfig = new Configuration(mConfiguration);
changes = newConfig.updateFrom(values);
@@ -18069,6 +18148,20 @@
null, false, false, MY_PID, Process.SYSTEM_UID, UserHandle.USER_ALL);
}
}
+ // Update the configuration with WM first and check if any of the stacks need to be
+ // resized due to the configuration change. If so, resize the stacks now and do any
+ // relaunches if necessary. This way we don't need to relaunch again below in
+ // ensureActivityConfigurationLocked().
+ if (mWindowManager != null) {
+ final int[] resizedStacks = mWindowManager.setNewConfiguration(mConfiguration);
+ if (resizedStacks != null) {
+ for (int stackId : resizedStacks) {
+ final Rect newBounds = mWindowManager.getBoundsForNewConfiguration(stackId);
+ mStackSupervisor.resizeStackLocked(
+ stackId, newBounds, null, null, false, false);
+ }
+ }
+ }
}
boolean kept = true;
@@ -18090,11 +18183,9 @@
!PRESERVE_WINDOWS);
}
}
-
- if (values != null && mWindowManager != null) {
- mWindowManager.setNewConfiguration(mConfiguration);
+ if (mWindowManager != null) {
+ mWindowManager.continueSurfaceLayout();
}
-
return kept;
}
@@ -18186,8 +18277,8 @@
return null;
}
- Association startAssociationLocked(int sourceUid, String sourceProcess, int targetUid,
- ComponentName targetComponent, String targetProcess) {
+ Association startAssociationLocked(int sourceUid, String sourceProcess, int sourceState,
+ int targetUid, ComponentName targetComponent, String targetProcess) {
if (!mTrackingAssociations) {
return null;
}
@@ -18216,7 +18307,8 @@
ass.mCount++;
ass.mNesting++;
if (ass.mNesting == 1) {
- ass.mStartTime = SystemClock.uptimeMillis();
+ ass.mStartTime = ass.mLastStateUptime = SystemClock.uptimeMillis();
+ ass.mLastState = sourceState;
}
return ass;
}
@@ -18245,7 +18337,39 @@
}
ass.mNesting--;
if (ass.mNesting == 0) {
- ass.mTime += SystemClock.uptimeMillis() - ass.mStartTime;
+ long uptime = SystemClock.uptimeMillis();
+ ass.mTime += uptime - ass.mStartTime;
+ ass.mStateTimes[ass.mLastState-ActivityManager.MIN_PROCESS_STATE]
+ += uptime - ass.mLastStateUptime;
+ ass.mLastState = ActivityManager.MAX_PROCESS_STATE + 2;
+ }
+ }
+
+ private void noteUidProcessState(final int uid, final int state) {
+ mBatteryStatsService.noteUidProcessState(uid, state);
+ if (mTrackingAssociations) {
+ for (int i1=0, N1=mAssociations.size(); i1<N1; i1++) {
+ ArrayMap<ComponentName, SparseArray<ArrayMap<String, Association>>> targetComponents
+ = mAssociations.valueAt(i1);
+ for (int i2=0, N2=targetComponents.size(); i2<N2; i2++) {
+ SparseArray<ArrayMap<String, Association>> sourceUids
+ = targetComponents.valueAt(i2);
+ ArrayMap<String, Association> sourceProcesses = sourceUids.get(uid);
+ if (sourceProcesses != null) {
+ for (int i4=0, N4=sourceProcesses.size(); i4<N4; i4++) {
+ Association ass = sourceProcesses.valueAt(i4);
+ if (ass.mNesting >= 1) {
+ // currently associated
+ long uptime = SystemClock.uptimeMillis();
+ ass.mStateTimes[ass.mLastState-ActivityManager.MIN_PROCESS_STATE]
+ += uptime - ass.mLastStateUptime;
+ ass.mLastState = state;
+ ass.mLastStateUptime = uptime;
+ }
+ }
+ }
+ }
+ }
}
}
@@ -18362,9 +18486,14 @@
for (int j = 0; j < activitiesSize; j++) {
final ActivityRecord r = app.activities.get(j);
if (r.app != app) {
- Slog.w(TAG, "Wtf, activity " + r + " in proc activity list not using proc "
- + app + "?!? Using " + r.app + " instead.");
- continue;
+ Log.wtf(TAG, "Found activity " + r + " in proc activity list using " + r.app
+ + " instead of expected " + app);
+ if (r.app == null || (r.app.uid == app.uid)) {
+ // Only fix things up when they look sane
+ r.app = app;
+ } else {
+ continue;
+ }
}
if (r.visible) {
// App has a visible activity; only upgrade adjustment.
@@ -20119,7 +20248,7 @@
}
uidRec.setProcState = uidRec.curProcState;
enqueueUidChangeLocked(uidRec, -1, uidChange);
- mBatteryStatsService.noteUidProcessState(uidRec.uid, uidRec.curProcState);
+ noteUidProcessState(uidRec.uid, uidRec.curProcState);
}
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
index 0253976..9be6b43 100644
--- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
+++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
@@ -16,12 +16,12 @@
package com.android.server.am;
+import android.app.ActivityManager;
import android.app.IActivityManager;
import android.os.RemoteException;
import android.os.ShellCommand;
import android.os.UserHandle;
-
-import com.android.internal.util.ArrayUtils;
+import android.util.DebugUtils;
import java.io.PrintWriter;
@@ -64,6 +64,8 @@
return runIsUserStopped(pw);
case "lenient-background-check":
return runLenientBackgroundCheck(pw);
+ case "get-uid-state":
+ return getUidState(pw);
default:
return handleDefaultCommands(cmd);
}
@@ -170,6 +172,17 @@
return 0;
}
+ int getUidState(PrintWriter pw) throws RemoteException {
+ mInternal.enforceCallingPermission(android.Manifest.permission.DUMP,
+ "getUidState()");
+ int state = mInternal.getUidState(Integer.parseInt(getNextArgRequired()));
+ pw.print(state);
+ pw.print(" (");
+ pw.printf(DebugUtils.valueToString(ActivityManager.class, "PROCESS_STATE_", state));
+ pw.println(")");
+ return 0;
+ }
+
@Override
public void onHelp() {
PrintWriter pw = getOutPrintWriter();
@@ -212,7 +225,7 @@
pw.println(" kill [--user <USER_ID> | all | current] <PACKAGE>");
pw.println(" Kill all processes associated with the given application.");
pw.println(" kill-all");
- pw.println(" Kill all processes that are safe to kill (cached, etc)");
+ pw.println(" Kill all processes that are safe to kill (cached, etc).");
pw.println(" write");
pw.println(" Write all pending state to storage.");
pw.println(" track-associations");
@@ -220,9 +233,11 @@
pw.println(" untrack-associations");
pw.println(" Disable and clear association tracking.");
pw.println(" is-user-stopped <USER_ID>");
- pw.println(" returns whether <USER_ID> has been stopped or not");
+ pw.println(" Returns whether <USER_ID> has been stopped or not.");
pw.println(" lenient-background-check [<true|false>]");
- pw.println(" optionally controls lenient background check mode, returns current mode.");
+ pw.println(" Optionally controls lenient background check mode, returns current mode.");
+ pw.println(" get-uid-state <UID>");
+ pw.println(" Gets the process state of an app given its <UID>.");
}
}
}
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index 5219827..48f87b6 100755
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -23,7 +23,6 @@
import static android.content.pm.ActivityInfo.FLAG_ALWAYS_FOCUSABLE;
import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE_AND_PIPABLE;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_CONFIGURATION;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_SAVED_STATE;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_SWITCH;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_THUMBNAILS;
import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_STATES;
@@ -452,24 +451,24 @@
}
}
- void scheduleMultiWindowChanged() {
+ void scheduleMultiWindowModeChanged() {
if (task == null || task.stack == null || app == null || app.thread == null) {
return;
}
try {
// An activity is considered to be in multi-window mode if its task isn't fullscreen.
- app.thread.scheduleMultiWindowChanged(appToken, !task.mFullscreen);
+ app.thread.scheduleMultiWindowModeChanged(appToken, !task.mFullscreen);
} catch (Exception e) {
// If process died, I don't care.
}
}
- void schedulePictureInPictureChanged() {
+ void schedulePictureInPictureModeChanged() {
if (task == null || task.stack == null || app == null || app.thread == null) {
return;
}
try {
- app.thread.schedulePictureInPictureChanged(
+ app.thread.schedulePictureInPictureModeChanged(
appToken, task.stack.mStackId == PINNED_STACK_ID);
} catch (Exception e) {
// If process died, no one cares.
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index e4ffde2..4ec1f61 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -1871,7 +1871,6 @@
// appropriate for it.
mStackSupervisor.mStoppingActivities.remove(r);
mStackSupervisor.mGoingToSleepActivities.remove(r);
- mStackSupervisor.mWaitingVisibleActivities.remove(r);
} catch (Exception e) {
// Just skip on any failure; we'll make it
// visible when it next restarts.
@@ -3090,10 +3089,14 @@
return false;
}
- if (stack.isHomeStack()) {
+ final ActivityRecord top = stack.topRunningActivityLocked();
+
+ if (stack.isHomeStack() && (top == null || !top.visible)) {
+ // If we will be focusing on the home stack next and its current top activity isn't
+ // visible, then use the task return to value to determine the home task to display next.
return mStackSupervisor.moveHomeStackTaskToTop(taskToReturnTo, reason);
}
- return mService.setFocusedActivityLocked(stack.topRunningActivityLocked(), myReason);
+ return mService.setFocusedActivityLocked(top, myReason);
}
final void stopActivityLocked(ActivityRecord r) {
@@ -4571,6 +4574,8 @@
}
r.configChangeFlags = 0;
+ r.deferRelaunchUntilPaused = false;
+ r.preserveWindowOnDeferredRelaunch = false;
}
boolean willActivityBeVisibleLocked(IBinder token) {
@@ -4784,6 +4789,8 @@
" Task id #" + task.taskId + "\n" +
" mFullscreen=" + task.mFullscreen + "\n" +
" mBounds=" + task.mBounds + "\n" +
+ " mMinimalWidth=" + task.mMinimalWidth + "\n" +
+ " mMinimalHeight=" + task.mMinimalHeight + "\n" +
" mLastNonFullscreenBounds=" + task.mLastNonFullscreenBounds);
if (printed) {
header = null;
@@ -4981,7 +4988,7 @@
private void postAddTask(TaskRecord task, ActivityStack prevStack) {
if (prevStack != null) {
- mStackSupervisor.scheduleReportPictureInPictureChangedIfNeeded(task, prevStack);
+ mStackSupervisor.scheduleReportPictureInPictureModeChangedIfNeeded(task, prevStack);
} else if (task.voiceSession != null) {
try {
task.voiceSession.taskStarted(task.intent, task.taskId);
@@ -5040,7 +5047,7 @@
r.setTask(task, null);
task.addActivityToTop(r);
setAppTask(r, task);
- mStackSupervisor.scheduleReportPictureInPictureChangedIfNeeded(task, prevStack);
+ mStackSupervisor.scheduleReportPictureInPictureModeChangedIfNeeded(task, prevStack);
moveToFrontAndResumeStateIfNeeded(r, wasFocused, wasResumed, "moveActivityToStack");
if (wasResumed) {
prevStack.mResumedActivity = null;
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 0e6d174..6c09178 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -102,7 +102,6 @@
import java.util.Objects;
import java.util.Set;
-import static android.Manifest.permission.MANAGE_ACTIVITY_STACKS;
import static android.Manifest.permission.START_ANY_ACTIVITY;
import static android.Manifest.permission.START_TASKS_FROM_RECENTS;
import static android.app.ActivityManager.LOCK_TASK_MODE_LOCKED;
@@ -1798,7 +1797,7 @@
// WM resizeTask must be done after the task is moved to the correct stack,
// because Task's setBounds() also updates dim layer's bounds, but that has
// dependency on the stack.
- mWindowManager.resizeTask(task.taskId, bounds, task.mOverrideConfig,
+ mWindowManager.resizeTask(task.taskId, task.mBounds, task.mOverrideConfig,
false /* relayout */, false /* forced */);
}
}
@@ -2070,14 +2069,16 @@
// static stacks need to be adjusted so they don't overlap with the docked stack.
// We get the bounds to use from window manager which has been adjusted for any
// screen controls and is also the same for all stacks.
- mWindowManager.getStackDockedModeBounds(
- HOME_STACK_ID, tempRect, true /* ignoreVisibility */);
+ if (dockedBounds != null) {
+ mWindowManager.getStackDockedModeBounds(
+ HOME_STACK_ID, tempRect, true /* ignoreVisibility */);
+ }
for (int i = FIRST_STATIC_STACK_ID; i <= LAST_STATIC_STACK_ID; i++) {
if (StackId.isResizeableByDockedStack(i)) {
ActivityStack otherStack = getStack(i);
if (otherStack != null) {
- resizeStackLocked(i, tempRect, tempOtherTaskBounds,
- tempOtherTaskInsetBounds, preserveWindows,
+ resizeStackLocked(i, dockedBounds != null ? tempRect : null,
+ tempOtherTaskBounds, tempOtherTaskInsetBounds, preserveWindows,
true /* allowResizeInDockedMode */);
}
}
@@ -2739,12 +2740,21 @@
// Called when WindowManager has finished animating the launchingBehind activity to the back.
void handleLaunchTaskBehindCompleteLocked(ActivityRecord r) {
- r.mLaunchTaskBehind = false;
final TaskRecord task = r.task;
- task.setLastThumbnailLocked(task.stack.screenshotActivitiesLocked(r));
+ final ActivityStack stack = task.stack;
+
+ r.mLaunchTaskBehind = false;
+ task.setLastThumbnailLocked(stack.screenshotActivitiesLocked(r));
mRecentTasks.addLocked(task);
mService.notifyTaskStackChangedLocked();
mWindowManager.setAppVisibility(r.appToken, false);
+
+ // When launching tasks behind, update the last active time of the top task after the new
+ // task has been shown briefly
+ final ActivityRecord top = stack.topActivity();
+ if (top != null) {
+ top.task.touchActiveTime();
+ }
}
void scheduleLaunchTaskBehindComplete(IBinder token) {
@@ -3524,7 +3534,7 @@
mActivityMetricsLogger.logWindowState();
}
- void scheduleReportMultiWindowChanged(TaskRecord task) {
+ void scheduleReportMultiWindowModeChanged(TaskRecord task) {
for (int i = task.mActivities.size() - 1; i >= 0; i--) {
final ActivityRecord r = task.mActivities.get(i);
if (r.app != null && r.app.thread != null) {
@@ -3537,7 +3547,7 @@
}
}
- void scheduleReportPictureInPictureChangedIfNeeded(TaskRecord task, ActivityStack prevStack) {
+ void scheduleReportPictureInPictureModeChangedIfNeeded(TaskRecord task, ActivityStack prevStack) {
final ActivityStack stack = task.stack;
if (prevStack == null || prevStack == stack
|| (prevStack.mStackId != PINNED_STACK_ID && stack.mStackId != PINNED_STACK_ID)) {
@@ -3575,7 +3585,7 @@
synchronized (mService) {
for (int i = mMultiWindowModeChangedActivities.size() - 1; i >= 0; i--) {
final ActivityRecord r = mMultiWindowModeChangedActivities.remove(i);
- r.scheduleMultiWindowChanged();
+ r.scheduleMultiWindowModeChanged();
}
}
} break;
@@ -3583,7 +3593,7 @@
synchronized (mService) {
for (int i = mPipModeChangedActivities.size() - 1; i >= 0; i--) {
final ActivityRecord r = mPipModeChangedActivities.remove(i);
- r.schedulePictureInPictureChanged();
+ r.schedulePictureInPictureModeChanged();
}
}
} break;
diff --git a/services/core/java/com/android/server/am/ActivityStarter.java b/services/core/java/com/android/server/am/ActivityStarter.java
index e3ca3ea..3bbc452 100644
--- a/services/core/java/com/android/server/am/ActivityStarter.java
+++ b/services/core/java/com/android/server/am/ActivityStarter.java
@@ -947,8 +947,6 @@
// We didn't do anything... but it was needed (a.k.a., client don't use that
// intent!) And for paranoia, make sure we have correctly resumed the top activity.
resumeTargetStackIfNeeded();
- mSupervisor.showNonResizeableDockToastIfNeeded(mStartActivity.task,
- preferredLaunchStackId, mTargetStack.mStackId);
return START_TASK_TO_FRONT;
}
}
@@ -989,7 +987,7 @@
top.deliverNewIntentLocked(
mCallingUid, mStartActivity.intent, mStartActivity.launchedFromPackage);
mSupervisor.showNonResizeableDockToastIfNeeded(mStartActivity.task,
- preferredLaunchStackId, mTargetStack.mStackId);
+ preferredLaunchStackId, topStack.mStackId);
return START_DELIVERED_TO_TOP;
}
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index ffa3b5b..3d42047 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -1224,7 +1224,8 @@
// WiFi keeps an accumulated total of stats, unlike Bluetooth.
// Keep the last WiFi stats so we can compute a delta.
@GuardedBy("mExternalStatsLock")
- private WifiActivityEnergyInfo mLastInfo = new WifiActivityEnergyInfo(0, 0, 0, 0, 0, 0);
+ private WifiActivityEnergyInfo mLastInfo =
+ new WifiActivityEnergyInfo(0, 0, 0, new long[]{0}, 0, 0, 0);
@GuardedBy("mExternalStatsLock")
private WifiActivityEnergyInfo pullWifiEnergyInfoLocked() {
diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java
index 45e3a76..37c7765 100644
--- a/services/core/java/com/android/server/am/BroadcastQueue.java
+++ b/services/core/java/com/android/server/am/BroadcastQueue.java
@@ -50,7 +50,6 @@
import android.util.Slog;
import android.util.TimeUtils;
import com.android.server.DeviceIdleController;
-import com.android.server.LocalServices;
import static com.android.server.am.ActivityManagerDebugConfig.*;
@@ -563,7 +562,7 @@
}
if (!skip) {
final int allowed = mService.checkAllowBackgroundLocked(filter.receiverList.uid,
- filter.packageName, -1);
+ filter.packageName, -1, true);
if (allowed == ActivityManager.APP_START_MODE_DISABLED) {
Slog.w(TAG, "Background execution not allowed: receiving "
+ r.intent
@@ -1102,21 +1101,21 @@
if (!skip) {
final int allowed = mService.checkAllowBackgroundLocked(
- info.activityInfo.applicationInfo.uid, info.activityInfo.packageName, -1);
+ info.activityInfo.applicationInfo.uid, info.activityInfo.packageName, -1,
+ false);
if (allowed != ActivityManager.APP_START_MODE_NORMAL) {
// We won't allow this receiver to be launched if the app has been
- // completely disabled from launches, or it is delayed and the broadcast
- // was not explicitly sent to it and this would result in a new process
- // for it being created.
+ // completely disabled from launches, or it was not explicitly sent
+ // to it and the app is in a state that should not receive it
+ // (depending on how checkAllowBackgroundLocked has determined that).
if (allowed == ActivityManager.APP_START_MODE_DISABLED) {
Slog.w(TAG, "Background execution disabled: receiving "
+ r.intent + " to "
+ component.flattenToShortString());
skip = true;
- }
- if (((r.intent.getFlags()&Intent.FLAG_RECEIVER_EXCLUDE_BACKGROUND) != 0)
+ } else if (((r.intent.getFlags()&Intent.FLAG_RECEIVER_EXCLUDE_BACKGROUND) != 0)
|| (r.intent.getComponent() == null
- && r.intent.getPackage() == null && app == null
+ && r.intent.getPackage() == null
&& ((r.intent.getFlags()
& Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND) == 0))) {
Slog.w(TAG, "Background execution not allowed: receiving "
diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index bacbd3e..93d4060 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -24,7 +24,8 @@
import android.util.DebugUtils;
import android.util.EventLog;
import android.util.Slog;
-import com.android.internal.app.ProcessStats;
+import com.android.internal.app.procstats.ProcessStats;
+import com.android.internal.app.procstats.ProcessState;
import com.android.internal.os.BatteryStatsImpl;
import android.app.ActivityManager;
@@ -69,7 +70,7 @@
IApplicationThread thread; // the actual proc... may be null only if
// 'persistent' is true (in which case we
// are in the process of launching the app)
- ProcessStats.ProcessState baseProcessTracker;
+ ProcessState baseProcessTracker;
BatteryStatsImpl.Uid.Proc curProcBatteryStats;
int pid; // The process of this application; 0 if none
int[] gids; // The gids this process was launched with
@@ -444,7 +445,7 @@
public void makeActive(IApplicationThread _thread, ProcessStatsService tracker) {
if (thread == null) {
- final ProcessStats.ProcessState origBase = baseProcessTracker;
+ final ProcessState origBase = baseProcessTracker;
if (origBase != null) {
origBase.setState(ProcessStats.STATE_NOTHING,
tracker.getMemFactorLocked(), SystemClock.uptimeMillis(), pkgList);
@@ -470,7 +471,7 @@
public void makeInactive(ProcessStatsService tracker) {
thread = null;
- final ProcessStats.ProcessState origBase = baseProcessTracker;
+ final ProcessState origBase = baseProcessTracker;
if (origBase != null) {
if (origBase != null) {
origBase.setState(ProcessStats.STATE_NOTHING,
@@ -559,7 +560,7 @@
}
EventLog.writeEvent(EventLogTags.AM_KILL, userId, pid, processName, setAdj, reason);
Process.killProcessQuiet(pid);
- Process.killProcessGroup(uid, pid);
+ ActivityManagerService.killProcessGroup(uid, pid);
if (!persistent) {
killed = true;
killedByAm = true;
@@ -696,7 +697,7 @@
}
pkgList.clear();
- ProcessStats.ProcessState ps = tracker.getProcessStateLocked(
+ ProcessState ps = tracker.getProcessStateLocked(
info.packageName, uid, info.versionCode, processName);
ProcessStats.ProcessStateHolder holder = new ProcessStats.ProcessStateHolder(
info.versionCode);
diff --git a/services/core/java/com/android/server/am/ProcessStartLogger.java b/services/core/java/com/android/server/am/ProcessStartLogger.java
deleted file mode 100644
index 39fbeb5..0000000
--- a/services/core/java/com/android/server/am/ProcessStartLogger.java
+++ /dev/null
@@ -1,151 +0,0 @@
-package com.android.server.am;
-
-import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
-import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
-
-import android.app.AppGlobals;
-import android.app.admin.SecurityLog;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.pm.ApplicationInfo;
-import android.os.Handler;
-import android.os.HandlerThread;
-import android.os.Process;
-import android.os.RemoteException;
-import android.os.Process.ProcessStartResult;
-import android.util.Slog;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.security.MessageDigest;
-import java.security.NoSuchAlgorithmException;
-import java.util.HashMap;
-
-/**
- * A class that logs process start information (including APK hash) to the security log.
- */
-class ProcessStartLogger {
- private static final String CLASS_NAME = "ProcessStartLogger";
- private static final String TAG = TAG_WITH_CLASS_NAME ? CLASS_NAME : TAG_AM;
-
- final HandlerThread mHandlerProcessLoggingThread;
- Handler mHandlerProcessLogging;
- // Should only access in mHandlerProcessLoggingThread
- final HashMap<String, String> mProcessLoggingApkHashes;
-
- ProcessStartLogger() {
- mHandlerProcessLoggingThread = new HandlerThread(CLASS_NAME,
- Process.THREAD_PRIORITY_BACKGROUND);
- mProcessLoggingApkHashes = new HashMap();
- }
-
- void logIfNeededLocked(ProcessRecord app, ProcessStartResult startResult) {
- if (!SecurityLog.isLoggingEnabled()) {
- return;
- }
- if (!mHandlerProcessLoggingThread.isAlive()) {
- mHandlerProcessLoggingThread.start();
- mHandlerProcessLogging = new Handler(mHandlerProcessLoggingThread.getLooper());
- }
- mHandlerProcessLogging.post(new ProcessLoggingRunnable(app, startResult,
- System.currentTimeMillis()));
- }
-
- void registerListener(Context context) {
- IntentFilter packageChangedFilter = new IntentFilter();
- packageChangedFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
- packageChangedFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);
- context.registerReceiver(new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- if (intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)
- || Intent.ACTION_PACKAGE_ADDED.equals(intent.getAction())) {
- int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
- getSendingUserId());
- String packageName = intent.getData().getSchemeSpecificPart();
- try {
- ApplicationInfo info = AppGlobals.getPackageManager().getApplicationInfo(
- packageName, 0, userHandle);
- invaildateCache(info.sourceDir);
- } catch (RemoteException e) {
- }
- }
- }
- }, packageChangedFilter);
- }
-
- private void invaildateCache(final String apkPath) {
- if (mHandlerProcessLogging != null) {
- mHandlerProcessLogging.post(new Runnable() {
- @Override
- public void run() {
- mProcessLoggingApkHashes.remove(apkPath);
- }
- });
- }
- }
-
- private class ProcessLoggingRunnable implements Runnable {
-
- private final ProcessRecord app;
- private final Process.ProcessStartResult startResult;
- private final long startTimestamp;
-
- public ProcessLoggingRunnable(ProcessRecord app, Process.ProcessStartResult startResult,
- long startTimestamp){
- this.app = app;
- this.startResult = startResult;
- this.startTimestamp = startTimestamp;
- }
-
- @Override
- public void run() {
- String apkHash = computeStringHashOfApk(app);
- SecurityLog.writeEvent(SecurityLog.TAG_APP_PROCESS_START,
- app.processName,
- startTimestamp,
- app.uid,
- startResult.pid,
- app.info.seinfo,
- apkHash);
- }
-
- private String computeStringHashOfApk(ProcessRecord app){
- final String apkFile = app.info.sourceDir;
- if(apkFile == null) {
- return "No APK";
- }
- String apkHash = mProcessLoggingApkHashes.get(apkFile);
- if (apkHash == null) {
- try {
- byte[] hash = computeHashOfApkFile(apkFile);
- StringBuilder sb = new StringBuilder();
- for (int i = 0; i < hash.length; i++) {
- sb.append(String.format("%02x", hash[i]));
- }
- apkHash = sb.toString();
- mProcessLoggingApkHashes.put(apkFile, apkHash);
- } catch (IOException | NoSuchAlgorithmException e) {
- Slog.w(TAG, "computeStringHashOfApk() failed", e);
- }
- }
- return apkHash != null ? apkHash : "Failed to count APK hash";
- }
-
- private byte[] computeHashOfApkFile(String packageArchiveLocation)
- throws IOException, NoSuchAlgorithmException {
- MessageDigest md = MessageDigest.getInstance("SHA-256");
- FileInputStream input = new FileInputStream(new File(packageArchiveLocation));
- byte[] buffer = new byte[65536];
- int size;
- while((size = input.read(buffer)) > 0) {
- md.update(buffer, 0, size);
- }
- input.close();
- return md.digest();
- }
- }
-}
\ No newline at end of file
diff --git a/services/core/java/com/android/server/am/ProcessStatsService.java b/services/core/java/com/android/server/am/ProcessStatsService.java
index 9634dff..8d2b1c2 100644
--- a/services/core/java/com/android/server/am/ProcessStatsService.java
+++ b/services/core/java/com/android/server/am/ProcessStatsService.java
@@ -28,8 +28,11 @@
import android.util.Slog;
import android.util.SparseArray;
import android.util.TimeUtils;
-import com.android.internal.app.IProcessStats;
-import com.android.internal.app.ProcessStats;
+import com.android.internal.app.procstats.DumpUtils;
+import com.android.internal.app.procstats.IProcessStats;
+import com.android.internal.app.procstats.ProcessState;
+import com.android.internal.app.procstats.ProcessStats;
+import com.android.internal.app.procstats.ServiceState;
import com.android.internal.os.BackgroundThread;
import java.io.File;
@@ -107,12 +110,12 @@
}
}
- public ProcessStats.ProcessState getProcessStateLocked(String packageName,
+ public ProcessState getProcessStateLocked(String packageName,
int uid, int versionCode, String processName) {
return mProcessStats.getProcessStateLocked(packageName, uid, versionCode, processName);
}
- public ProcessStats.ServiceState getServiceStateLocked(String packageName, int uid,
+ public ServiceState getServiceStateLocked(String packageName, int uid,
int versionCode, String processName, String className) {
return mProcessStats.getServiceStateLocked(packageName, uid, versionCode, processName,
className);
@@ -143,22 +146,10 @@
final SparseArray<ProcessStats.PackageState> vers = uids.valueAt(iuid);
for (int iver=vers.size()-1; iver>=0; iver--) {
final ProcessStats.PackageState pkg = vers.valueAt(iver);
- final ArrayMap<String, ProcessStats.ServiceState> services = pkg.mServices;
+ final ArrayMap<String, ServiceState> services = pkg.mServices;
for (int isvc=services.size()-1; isvc>=0; isvc--) {
- final ProcessStats.ServiceState service = services.valueAt(isvc);
- if (service.isRestarting()) {
- service.setRestarting(true, memFactor, now);
- } else if (service.isInUse()) {
- if (service.mStartedState != ProcessStats.STATE_NOTHING) {
- service.setStarted(true, memFactor, now);
- }
- if (service.mBoundState != ProcessStats.STATE_NOTHING) {
- service.setBound(true, memFactor, now);
- }
- if (service.mExecState != ProcessStats.STATE_NOTHING) {
- service.setExecuting(true, memFactor, now);
- }
- }
+ final ServiceState service = services.valueAt(isvc);
+ service.setMemFactor(memFactor, now);
}
}
}
@@ -294,12 +285,11 @@
if (stats.mReadError != null) {
Slog.w(TAG, "Ignoring existing stats; " + stats.mReadError);
if (DEBUG) {
- ArrayMap<String, SparseArray<ProcessStats.ProcessState>> procMap
- = stats.mProcesses.getMap();
+ ArrayMap<String, SparseArray<ProcessState>> procMap = stats.mProcesses.getMap();
final int NPROC = procMap.size();
for (int ip=0; ip<NPROC; ip++) {
Slog.w(TAG, "Process: " + procMap.keyAt(ip));
- SparseArray<ProcessStats.ProcessState> uids = procMap.valueAt(ip);
+ SparseArray<ProcessState> uids = procMap.valueAt(ip);
final int NUID = uids.size();
for (int iu=0; iu<NUID; iu++) {
Slog.w(TAG, " Uid " + uids.keyAt(iu) + ": " + uids.valueAt(iu));
@@ -387,13 +377,13 @@
boolean dumpFilteredProcessesCsvLocked(PrintWriter pw, String header,
boolean sepScreenStates, int[] screenStates, boolean sepMemStates, int[] memStates,
boolean sepProcStates, int[] procStates, long now, String reqPackage) {
- ArrayList<ProcessStats.ProcessState> procs = mProcessStats.collectProcessesLocked(
+ ArrayList<ProcessState> procs = mProcessStats.collectProcessesLocked(
screenStates, memStates, procStates, procStates, now, reqPackage, false);
if (procs.size() > 0) {
if (header != null) {
pw.println(header);
}
- ProcessStats.dumpProcessListCsv(pw, procs, sepScreenStates, screenStates,
+ DumpUtils.dumpProcessListCsv(pw, procs, sepScreenStates, screenStates,
sepMemStates, memStates, sepProcStates, procStates, now);
return true;
}
@@ -668,8 +658,8 @@
}
boolean[] sep = new boolean[1];
String[] error = new String[1];
- csvScreenStats = parseStateList(ProcessStats.ADJ_SCREEN_NAMES_CSV, ProcessStats.ADJ_SCREEN_MOD,
- args[i], sep, error);
+ csvScreenStats = parseStateList(DumpUtils.ADJ_SCREEN_NAMES_CSV,
+ ProcessStats.ADJ_SCREEN_MOD, args[i], sep, error);
if (csvScreenStats == null) {
pw.println("Error in \"" + args[i] + "\": " + error[0]);
dumpHelp(pw);
@@ -685,7 +675,8 @@
}
boolean[] sep = new boolean[1];
String[] error = new String[1];
- csvMemStats = parseStateList(ProcessStats.ADJ_MEM_NAMES_CSV, 1, args[i], sep, error);
+ csvMemStats = parseStateList(DumpUtils.ADJ_MEM_NAMES_CSV, 1, args[i],
+ sep, error);
if (csvMemStats == null) {
pw.println("Error in \"" + args[i] + "\": " + error[0]);
dumpHelp(pw);
@@ -701,7 +692,8 @@
}
boolean[] sep = new boolean[1];
String[] error = new String[1];
- csvProcStats = parseStateList(ProcessStats.STATE_NAMES_CSV, 1, args[i], sep, error);
+ csvProcStats = parseStateList(DumpUtils.STATE_NAMES_CSV, 1, args[i],
+ sep, error);
if (csvProcStats == null) {
pw.println("Error in \"" + args[i] + "\": " + error[0]);
dumpHelp(pw);
@@ -839,19 +831,19 @@
if (!csvSepScreenStats) {
for (int i=0; i<csvScreenStats.length; i++) {
pw.print(" ");
- ProcessStats.printScreenLabelCsv(pw, csvScreenStats[i]);
+ DumpUtils.printScreenLabelCsv(pw, csvScreenStats[i]);
}
}
if (!csvSepMemStats) {
for (int i=0; i<csvMemStats.length; i++) {
pw.print(" ");
- ProcessStats.printMemLabelCsv(pw, csvMemStats[i]);
+ DumpUtils.printMemLabelCsv(pw, csvMemStats[i]);
}
}
if (!csvSepProcStats) {
for (int i=0; i<csvProcStats.length; i++) {
pw.print(" ");
- pw.print(ProcessStats.STATE_NAMES_CSV[csvProcStats[i]]);
+ pw.print(DumpUtils.STATE_NAMES_CSV[csvProcStats[i]]);
}
}
pw.println();
diff --git a/services/core/java/com/android/server/am/ServiceRecord.java b/services/core/java/com/android/server/am/ServiceRecord.java
index 87cb40e..5075c3a 100644
--- a/services/core/java/com/android/server/am/ServiceRecord.java
+++ b/services/core/java/com/android/server/am/ServiceRecord.java
@@ -16,7 +16,7 @@
package com.android.server.am;
-import com.android.internal.app.ProcessStats;
+import com.android.internal.app.procstats.ServiceState;
import com.android.internal.os.BatteryStatsImpl;
import com.android.server.LocalServices;
import com.android.server.notification.NotificationManagerInternal;
@@ -88,8 +88,8 @@
ProcessRecord app; // where this service is running or null.
ProcessRecord isolatedProc; // keep track of isolated process, if requested
- ProcessStats.ServiceState tracker; // tracking service execution, may be null
- ProcessStats.ServiceState restartTracker; // tracking service restart
+ ServiceState tracker; // tracking service execution, may be null
+ ServiceState restartTracker; // tracking service restart
boolean delayed; // are we waiting to start this service in the background?
boolean isForeground; // is service currently in foreground mode?
int foregroundId; // Notification ID of last foreground req.
@@ -326,7 +326,7 @@
createdFromFg = callerIsFg;
}
- public ProcessStats.ServiceState getTracker() {
+ public ServiceState getTracker() {
if (tracker != null) {
return tracker;
}
diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java
index d7a1920..e32d1d1 100644
--- a/services/core/java/com/android/server/am/TaskRecord.java
+++ b/services/core/java/com/android/server/am/TaskRecord.java
@@ -126,10 +126,14 @@
private static final String ATTR_RESIZE_MODE = "resize_mode";
private static final String ATTR_PRIVILEGED = "privileged";
private static final String ATTR_NON_FULLSCREEN_BOUNDS = "non_fullscreen_bounds";
+ private static final String ATTR_MINIMAL_WIDTH = "minimal_width";
+ private static final String ATTR_MINIMAL_HEIGHT = "minimal_height";
+
private static final String TASK_THUMBNAIL_SUFFIX = "_task_thumbnail";
static final int INVALID_TASK_ID = -1;
+ static final int INVALID_MINIMAL_SIZE = -1;
final int taskId; // Unique identifier for this task.
String affinity; // The affinity name for this task, or null; may change identity.
@@ -281,6 +285,7 @@
mCallingPackage = info.packageName;
setIntent(_intent, info);
setMinDimensions(info);
+ touchActiveTime();
}
TaskRecord(ActivityManagerService service, int _taskId, ActivityInfo info, Intent _intent,
@@ -311,6 +316,7 @@
taskType = APPLICATION_ACTIVITY_TYPE;
mTaskToReturnTo = HOME_ACTIVITY_TYPE;
lastTaskDescription = _taskDescription;
+ touchActiveTime();
}
private TaskRecord(ActivityManagerService service, int _taskId, Intent _intent,
@@ -323,7 +329,7 @@
TaskThumbnailInfo lastThumbnailInfo, int taskAffiliation, int prevTaskId,
int nextTaskId, int taskAffiliationColor, int callingUid, String callingPackage,
int resizeMode, boolean privileged, boolean _realActivitySuspended,
- boolean userSetupComplete) {
+ boolean userSetupComplete, int minimalWidth, int minimalHeight) {
mService = service;
mFilename = String.valueOf(_taskId) + TASK_THUMBNAIL_SUFFIX +
TaskPersister.IMAGE_EXTENSION;
@@ -363,8 +369,8 @@
mCallingPackage = callingPackage;
mResizeMode = resizeMode;
mPrivileged = privileged;
- ActivityInfo info = (mActivities.size() > 0) ? mActivities.get(0).info : null;
- setMinDimensions(info);
+ mMinimalWidth = minimalWidth;
+ mMinimalHeight = minimalHeight;
}
void touchActiveTime() {
@@ -476,8 +482,8 @@
mMinimalWidth = info.windowLayout.minimalWidth;
mMinimalHeight = info.windowLayout.minimalHeight;
} else {
- mMinimalWidth = -1;
- mMinimalHeight = -1;
+ mMinimalWidth = INVALID_MINIMAL_SIZE;
+ mMinimalHeight = INVALID_MINIMAL_SIZE;
}
}
@@ -1146,6 +1152,8 @@
out.attribute(
null, ATTR_NON_FULLSCREEN_BOUNDS, mLastNonFullscreenBounds.flattenToString());
}
+ out.attribute(null, ATTR_MINIMAL_WIDTH, String.valueOf(mMinimalWidth));
+ out.attribute(null, ATTR_MINIMAL_HEIGHT, String.valueOf(mMinimalHeight));
if (affinityIntent != null) {
out.startTag(null, TAG_AFFINITYINTENT);
@@ -1210,6 +1218,8 @@
int resizeMode = RESIZE_MODE_FORCE_RESIZEABLE;
boolean privileged = false;
Rect bounds = null;
+ int minimalWidth = INVALID_MINIMAL_SIZE;
+ int minimalHeight = INVALID_MINIMAL_SIZE;
for (int attrNdx = in.getAttributeCount() - 1; attrNdx >= 0; --attrNdx) {
final String attrName = in.getAttributeName(attrNdx);
@@ -1277,6 +1287,10 @@
privileged = Boolean.valueOf(attrValue);
} else if (ATTR_NON_FULLSCREEN_BOUNDS.equals(attrName)) {
bounds = Rect.unflattenFromString(attrValue);
+ } else if (ATTR_MINIMAL_WIDTH.equals(attrName)) {
+ minimalWidth = Integer.valueOf(attrValue);
+ } else if (ATTR_MINIMAL_HEIGHT.equals(attrName)) {
+ minimalHeight = Integer.valueOf(attrValue);
} else {
Slog.w(TAG, "TaskRecord: Unknown attribute=" + attrName);
}
@@ -1337,7 +1351,7 @@
activities, firstActiveTime, lastActiveTime, lastTimeOnTop, neverRelinquishIdentity,
taskDescription, thumbnailInfo, taskAffiliation, prevTaskId, nextTaskId,
taskAffiliationColor, callingUid, callingPackage, resizeMode, privileged,
- realActivitySuspended, userSetupComplete);
+ realActivitySuspended, userSetupComplete, minimalWidth, minimalHeight);
task.updateOverrideConfiguration(bounds);
for (int activityNdx = activities.size() - 1; activityNdx >=0; --activityNdx) {
@@ -1358,10 +1372,10 @@
// so that the user can not render the task too small to manipulate. We don't need
// to do this for the pinned stack as the bounds are controlled by the system.
if (stack.mStackId != PINNED_STACK_ID) {
- if (minimalWidth == -1) {
+ if (minimalWidth == INVALID_MINIMAL_SIZE) {
minimalWidth = mService.mStackSupervisor.mDefaultMinimalSizeOfResizeableTask;
}
- if (minimalHeight == -1) {
+ if (minimalHeight == INVALID_MINIMAL_SIZE) {
minimalHeight = mService.mStackSupervisor.mDefaultMinimalSizeOfResizeableTask;
}
}
@@ -1437,7 +1451,7 @@
}
if (mFullscreen != oldFullscreen) {
- mService.mStackSupervisor.scheduleReportMultiWindowChanged(this);
+ mService.mStackSupervisor.scheduleReportMultiWindowModeChanged(this);
}
return !mOverrideConfig.equals(oldConfig) ? mOverrideConfig : null;
@@ -1518,6 +1532,9 @@
Rect updateOverrideConfigurationFromLaunchBounds() {
final Rect bounds = validateBounds(getLaunchBounds());
updateOverrideConfiguration(bounds);
+ if (bounds != null) {
+ bounds.set(mBounds);
+ }
return bounds;
}
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index c59591e9..aef454e 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -434,35 +434,17 @@
stoppingIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
stoppingIntent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
stoppingIntent.putExtra(Intent.EXTRA_SHUTDOWN_USERSPACE_ONLY, true);
- final Intent shutdownIntent = new Intent(Intent.ACTION_SHUTDOWN);
- // This is the result receiver for the final shutdown broadcast.
- final IIntentReceiver shutdownReceiver = new IIntentReceiver.Stub() {
- @Override
- public void performReceive(Intent intent, int resultCode, String data,
- Bundle extras, boolean ordered, boolean sticky, int sendingUser) {
- finishUserStop(uss);
- }
- };
// This is the result receiver for the initial stopping broadcast.
final IIntentReceiver stoppingReceiver = new IIntentReceiver.Stub() {
@Override
public void performReceive(Intent intent, int resultCode, String data,
Bundle extras, boolean ordered, boolean sticky, int sendingUser) {
- // On to the next.
- synchronized (mService) {
- if (uss.state != UserState.STATE_STOPPING) {
- // Whoops, we are being started back up. Abort, abort!
- return;
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ finishUserStopping(userId, uss);
}
- uss.setState(UserState.STATE_SHUTDOWN);
- }
- mService.mBatteryStatsService.noteEvent(
- BatteryStats.HistoryItem.EVENT_USER_RUNNING_FINISH,
- Integer.toString(userId), userId);
- mService.mSystemServiceManager.stopUser(userId);
- mService.broadcastIntentLocked(null, null, shutdownIntent,
- null, shutdownReceiver, 0, null, null, null, AppOpsManager.OP_NONE,
- null, true, false, MY_PID, SYSTEM_UID, userId);
+ });
}
};
// Kick things off.
@@ -476,7 +458,45 @@
}
}
- void finishUserStop(UserState uss) {
+ void finishUserStopping(final int userId, final UserState uss) {
+ // On to the next.
+ final Intent shutdownIntent = new Intent(Intent.ACTION_SHUTDOWN);
+ // This is the result receiver for the final shutdown broadcast.
+ final IIntentReceiver shutdownReceiver = new IIntentReceiver.Stub() {
+ @Override
+ public void performReceive(Intent intent, int resultCode, String data,
+ Bundle extras, boolean ordered, boolean sticky, int sendingUser) {
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ finishUserStopped(uss);
+ }
+ });
+ }
+ };
+
+ synchronized (mService) {
+ if (uss.state != UserState.STATE_STOPPING) {
+ // Whoops, we are being started back up. Abort, abort!
+ return;
+ }
+ uss.setState(UserState.STATE_SHUTDOWN);
+ }
+
+ mService.mBatteryStatsService.noteEvent(
+ BatteryStats.HistoryItem.EVENT_USER_RUNNING_FINISH,
+ Integer.toString(userId), userId);
+ mService.mSystemServiceManager.stopUser(userId);
+
+ synchronized (mService) {
+ mService.broadcastIntentLocked(null, null, shutdownIntent,
+ null, shutdownReceiver, 0, null, null, null,
+ AppOpsManager.OP_NONE,
+ null, true, false, MY_PID, SYSTEM_UID, userId);
+ }
+ }
+
+ void finishUserStopped(UserState uss) {
final int userId = uss.mHandle.getIdentifier();
boolean stopped;
ArrayList<IStopUserCallback> callbacks;
@@ -765,10 +785,17 @@
intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
mService.broadcastIntentLocked(null, null, intent, null,
new IIntentReceiver.Stub() {
+ @Override
public void performReceive(Intent intent, int resultCode,
String data, Bundle extras, boolean ordered,
boolean sticky, int sendingUser) {
- onUserInitialized(uss, foreground, oldUserId, userId);
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ onUserInitialized(uss, foreground,
+ oldUserId, userId);
+ }
+ });
}
}, 0, null, null, null, AppOpsManager.OP_NONE,
null, true, false, MY_PID, SYSTEM_UID, userId);
diff --git a/services/core/java/com/android/server/backup/BackupUtils.java b/services/core/java/com/android/server/backup/BackupUtils.java
new file mode 100644
index 0000000..e5d564d
--- /dev/null
+++ b/services/core/java/com/android/server/backup/BackupUtils.java
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.backup;
+
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.Signature;
+import android.util.Slog;
+
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+public class BackupUtils {
+ private static final String TAG = "BackupUtils";
+
+ private static final boolean DEBUG = false; // STOPSHIP if true
+
+ public static boolean signaturesMatch(ArrayList<byte[]> storedSigHashes, PackageInfo target) {
+ if (target == null) {
+ return false;
+ }
+
+ // If the target resides on the system partition, we allow it to restore
+ // data from the like-named package in a restore set even if the signatures
+ // do not match. (Unlike general applications, those flashed to the system
+ // partition will be signed with the device's platform certificate, so on
+ // different phones the same system app will have different signatures.)
+ if ((target.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
+ if (DEBUG) Slog.v(TAG, "System app " + target.packageName + " - skipping sig check");
+ return true;
+ }
+
+ // Allow unsigned apps, but not signed on one device and unsigned on the other
+ // !!! TODO: is this the right policy?
+ Signature[] deviceSigs = target.signatures;
+ if (DEBUG) Slog.v(TAG, "signaturesMatch(): stored=" + storedSigHashes
+ + " device=" + deviceSigs);
+ if ((storedSigHashes == null || storedSigHashes.size() == 0)
+ && (deviceSigs == null || deviceSigs.length == 0)) {
+ return true;
+ }
+ if (storedSigHashes == null || deviceSigs == null) {
+ return false;
+ }
+
+ // !!! TODO: this demands that every stored signature match one
+ // that is present on device, and does not demand the converse.
+ // Is this this right policy?
+ final int nStored = storedSigHashes.size();
+ final int nDevice = deviceSigs.length;
+
+ // hash each on-device signature
+ ArrayList<byte[]> deviceHashes = new ArrayList<byte[]>(nDevice);
+ for (int i = 0; i < nDevice; i++) {
+ deviceHashes.add(hashSignature(deviceSigs[i]));
+ }
+
+ // now ensure that each stored sig (hash) matches an on-device sig (hash)
+ for (int n = 0; n < nStored; n++) {
+ boolean match = false;
+ final byte[] storedHash = storedSigHashes.get(n);
+ for (int i = 0; i < nDevice; i++) {
+ if (Arrays.equals(storedHash, deviceHashes.get(i))) {
+ match = true;
+ break;
+ }
+ }
+ // match is false when no on-device sig matched one of the stored ones
+ if (!match) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ public static byte[] hashSignature(byte[] signature) {
+ try {
+ MessageDigest digest = MessageDigest.getInstance("SHA-256");
+ digest.update(signature);
+ return digest.digest();
+ } catch (NoSuchAlgorithmException e) {
+ Slog.w(TAG, "No SHA-256 algorithm found!");
+ }
+ return null;
+ }
+
+ public static byte[] hashSignature(Signature signature) {
+ return hashSignature(signature.toByteArray());
+ }
+
+ public static ArrayList<byte[]> hashSignatureArray(Signature[] sigs) {
+ if (sigs == null) {
+ return null;
+ }
+
+ ArrayList<byte[]> hashes = new ArrayList<>(sigs.length);
+ for (Signature s : sigs) {
+ hashes.add(hashSignature(s));
+ }
+ return hashes;
+ }
+
+ public static ArrayList<byte[]> hashSignatureArray(List<byte[]> sigs) {
+ if (sigs == null) {
+ return null;
+ }
+
+ ArrayList<byte[]> hashes = new ArrayList<>(sigs.size());
+ for (byte[] s : sigs) {
+ hashes.add(hashSignature(s));
+ }
+ return hashes;
+ }
+}
diff --git a/services/core/java/com/android/server/connectivity/MetricsLoggerService.java b/services/core/java/com/android/server/connectivity/MetricsLoggerService.java
index 7cac227..f91db78 100644
--- a/services/core/java/com/android/server/connectivity/MetricsLoggerService.java
+++ b/services/core/java/com/android/server/connectivity/MetricsLoggerService.java
@@ -18,18 +18,21 @@
import com.android.server.SystemService;
+import android.app.PendingIntent;
import android.content.Context;
+import android.content.pm.PackageManager;
import android.net.ConnectivityMetricsEvent;
import android.net.ConnectivityMetricsLogger;
import android.net.IConnectivityMetricsLogger;
-import android.net.IConnectivityMetricsLoggerSubscriber;
-import android.os.IBinder;
-import android.os.RemoteException;
-import android.util.ArrayMap;
+import android.os.Binder;
+import android.os.Parcel;
+import android.text.format.DateUtils;
import android.util.Log;
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.ArrayDeque;
import java.util.ArrayList;
-import java.util.List;
/** {@hide} */
public class MetricsLoggerService extends SystemService {
@@ -43,134 +46,307 @@
@Override
public void onStart() {
+ resetThrottlingCounters(System.currentTimeMillis());
}
@Override
public void onBootPhase(int phase) {
if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) {
- Log.d(TAG, "onBootPhase: PHASE_SYSTEM_SERVICES_READY");
+ if (DBG) Log.d(TAG, "onBootPhase: PHASE_SYSTEM_SERVICES_READY");
publishBinderService(ConnectivityMetricsLogger.CONNECTIVITY_METRICS_LOGGER_SERVICE,
mBinder);
}
}
- private final int MAX_NUMBER_OF_EVENTS = 100;
- private final int MAX_TIME_OFFSET = 15*60*1000; // 15 minutes
- private final List<ConnectivityMetricsEvent> mEvents = new ArrayList<>();
- private long mLastSentEventTimeMillis = System.currentTimeMillis();
+ // TODO: read from system property
+ private final int MAX_NUMBER_OF_EVENTS = 1000;
- private final void enforceConnectivityInternalPermission() {
+ // TODO: read from system property
+ private final int EVENTS_NOTIFICATION_THRESHOLD = 300;
+
+ // TODO: read from system property
+ private final int THROTTLING_TIME_INTERVAL_MILLIS = 60 * 60 * 1000; // 1 hour
+
+ // TODO: read from system property
+ private final int THROTTLING_MAX_NUMBER_OF_MESSAGES_PER_COMPONENT = 1000;
+
+ private int mEventCounter = 0;
+
+ /**
+ * Reference of the last event in the list of cached events.
+ *
+ * When client of this service retrieves events by calling getEvents, it is passing
+ * ConnectivityMetricsEvent.Reference object. After getEvents returns, that object will
+ * contain this reference. The client can save it and use next time it calls getEvents.
+ * This way only new events will be returned.
+ */
+ private long mLastEventReference = 0;
+
+ private final int mThrottlingCounters[] =
+ new int[ConnectivityMetricsLogger.NUMBER_OF_COMPONENTS];
+
+ private long mThrottlingIntervalBoundaryMillis;
+
+ private final ArrayDeque<ConnectivityMetricsEvent> mEvents = new ArrayDeque<>();
+
+ private void enforceConnectivityInternalPermission() {
getContext().enforceCallingOrSelfPermission(
android.Manifest.permission.CONNECTIVITY_INTERNAL,
"MetricsLoggerService");
}
+ private void enforceDumpPermission() {
+ getContext().enforceCallingOrSelfPermission(
+ android.Manifest.permission.DUMP,
+ "MetricsLoggerService");
+ }
+
+ private void resetThrottlingCounters(long currentTimeMillis) {
+ for (int i = 0; i < mThrottlingCounters.length; i++) {
+ mThrottlingCounters[i] = 0;
+ }
+ mThrottlingIntervalBoundaryMillis =
+ currentTimeMillis + THROTTLING_TIME_INTERVAL_MILLIS;
+ }
+
+ private void addEvent(ConnectivityMetricsEvent e) {
+ if (VDBG) {
+ Log.v(TAG, "writeEvent(" + e.toString() + ")");
+ }
+
+ while (mEvents.size() >= MAX_NUMBER_OF_EVENTS) {
+ mEvents.removeFirst();
+ }
+
+ mEvents.addLast(e);
+ }
+
/**
* Implementation of the IConnectivityMetricsLogger interface.
*/
private final IConnectivityMetricsLogger.Stub mBinder = new IConnectivityMetricsLogger.Stub() {
- private final ArrayMap<IConnectivityMetricsLoggerSubscriber,
- IBinder.DeathRecipient> mSubscribers = new ArrayMap<>();
+ private final ArrayList<PendingIntent> mPendingIntents = new ArrayList<>();
-
- private ConnectivityMetricsEvent[] prepareEventsToSendIfReady() {
- ConnectivityMetricsEvent[] eventsToSend = null;
- final long currentTimeMillis = System.currentTimeMillis();
- final long timeOffset = currentTimeMillis - mLastSentEventTimeMillis;
- if (timeOffset >= MAX_TIME_OFFSET
- || timeOffset < 0 // system time has changed
- || mEvents.size() >= MAX_NUMBER_OF_EVENTS) {
- // batch events
- mLastSentEventTimeMillis = currentTimeMillis;
- eventsToSend = new ConnectivityMetricsEvent[mEvents.size()];
- mEvents.toArray(eventsToSend);
- mEvents.clear();
+ @Override
+ protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ if (getContext().checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
+ != PackageManager.PERMISSION_GRANTED) {
+ pw.println("Permission Denial: can't dump ConnectivityMetricsLoggerService " +
+ "from from pid=" + Binder.getCallingPid() + ", uid=" +
+ Binder.getCallingUid());
+ return;
}
- return eventsToSend;
- }
- private void maybeSendEventsToSubscribers(ConnectivityMetricsEvent[] eventsToSend) {
- if (eventsToSend == null || eventsToSend.length == 0) return;
- synchronized (mSubscribers) {
- for (IConnectivityMetricsLoggerSubscriber s : mSubscribers.keySet()) {
- try {
- s.onEvents(eventsToSend);
- } catch (RemoteException ex) {
- Log.e(TAG, "RemoteException " + ex);
- }
- }
- }
- }
+ boolean dumpSerializedSize = false;
+ boolean dumpEvents = false;
+ for (String arg : args) {
+ switch (arg) {
+ case "--events":
+ dumpEvents = true;
+ break;
- public void logEvent(ConnectivityMetricsEvent event) {
- ConnectivityMetricsEvent[] events = new ConnectivityMetricsEvent[]{event};
- logEvents(events);
- }
+ case "--size":
+ dumpSerializedSize = true;
+ break;
- public void logEvents(ConnectivityMetricsEvent[] events) {
- enforceConnectivityInternalPermission();
- ConnectivityMetricsEvent[] eventsToSend;
-
- if (VDBG) {
- for (ConnectivityMetricsEvent e : events) {
- Log.v(TAG, "writeEvent(" + e.toString() + ")");
+ case "--all":
+ dumpEvents = true;
+ dumpSerializedSize = true;
+ break;
}
}
synchronized (mEvents) {
- for (ConnectivityMetricsEvent e : events) {
- mEvents.add(e);
+ pw.println("Number of events: " + mEvents.size());
+ pw.println("Time span: " +
+ DateUtils.formatElapsedTime(
+ (System.currentTimeMillis() - mEvents.peekFirst().timestamp)
+ / 1000));
+
+ if (dumpSerializedSize) {
+ long dataSize = 0;
+ Parcel p = Parcel.obtain();
+ for (ConnectivityMetricsEvent e : mEvents) {
+ dataSize += 16; // timestamp and 2 stamps
+
+ p.writeParcelable(e.data, 0);
+ }
+ dataSize += p.dataSize();
+ p.recycle();
+ pw.println("Serialized data size: " + dataSize);
}
- eventsToSend = prepareEventsToSendIfReady();
+ if (dumpEvents) {
+ pw.println();
+ pw.println("Events:");
+ for (ConnectivityMetricsEvent e : mEvents) {
+ pw.println(e.toString());
+ }
+ }
}
- maybeSendEventsToSubscribers(eventsToSend);
+ if (!mPendingIntents.isEmpty()) {
+ pw.println();
+ pw.println("Pending intents:");
+ for (PendingIntent pi : mPendingIntents) {
+ pw.println(pi.toString());
+ }
+ }
}
- public boolean subscribe(IConnectivityMetricsLoggerSubscriber subscriber) {
- enforceConnectivityInternalPermission();
- if (VDBG) Log.v(TAG, "subscribe");
+ public long logEvent(ConnectivityMetricsEvent event) {
+ ConnectivityMetricsEvent[] events = new ConnectivityMetricsEvent[]{event};
+ return logEvents(events);
+ }
- synchronized (mSubscribers) {
- if (mSubscribers.containsKey(subscriber)) {
- Log.e(TAG, "subscriber is already subscribed");
- return false;
+ /**
+ * @param events
+ *
+ * Note: All events must belong to the same component.
+ *
+ * @return 0 on success
+ * <0 if error happened
+ * >0 timestamp after which new events will be accepted
+ */
+ public long logEvents(ConnectivityMetricsEvent[] events) {
+ enforceConnectivityInternalPermission();
+
+ if (events == null || events.length == 0) {
+ Log.wtf(TAG, "No events passed to logEvents()");
+ return -1;
+ }
+
+ int componentTag = events[0].componentTag;
+ if (componentTag < 0 ||
+ componentTag >= ConnectivityMetricsLogger.NUMBER_OF_COMPONENTS) {
+ Log.wtf(TAG, "Unexpected tag: " + componentTag);
+ return -1;
+ }
+
+ synchronized (mThrottlingCounters) {
+ long currentTimeMillis = System.currentTimeMillis();
+ if (currentTimeMillis > mThrottlingIntervalBoundaryMillis) {
+ resetThrottlingCounters(currentTimeMillis);
}
- final IConnectivityMetricsLoggerSubscriber s = subscriber;
- IBinder.DeathRecipient dr = new IBinder.DeathRecipient() {
- @Override
- public void binderDied() {
- if (VDBG) Log.v(TAG, "subscriber died");
- synchronized (mSubscribers) {
- mSubscribers.remove(s);
+
+ mThrottlingCounters[componentTag] += events.length;
+
+ if (mThrottlingCounters[componentTag] >
+ THROTTLING_MAX_NUMBER_OF_MESSAGES_PER_COMPONENT) {
+ Log.w(TAG, "Too many events from #" + componentTag +
+ ". Block until " + mThrottlingIntervalBoundaryMillis);
+
+ return mThrottlingIntervalBoundaryMillis;
+ }
+ }
+
+ boolean sendPendingIntents = false;
+
+ synchronized (mEvents) {
+ for (ConnectivityMetricsEvent e : events) {
+ if (e.componentTag != componentTag) {
+ Log.wtf(TAG, "Unexpected tag: " + e.componentTag);
+ return -1;
+ }
+
+ addEvent(e);
+ }
+
+ mLastEventReference += events.length;
+
+ mEventCounter += events.length;
+ if (mEventCounter >= EVENTS_NOTIFICATION_THRESHOLD) {
+ mEventCounter = 0;
+ sendPendingIntents = true;
+ }
+ }
+
+ if (sendPendingIntents) {
+ synchronized (mPendingIntents) {
+ for (PendingIntent pi : mPendingIntents) {
+ if (VDBG) Log.v(TAG, "Send pending intent");
+ try {
+ pi.send(getContext(), 0, null, null, null);
+ } catch (PendingIntent.CanceledException e) {
+ Log.e(TAG, "Pending intent canceled: " + pi);
+ mPendingIntents.remove(pi);
}
}
- };
-
- try {
- subscriber.asBinder().linkToDeath(dr, 0);
- mSubscribers.put(subscriber, dr);
- } catch (RemoteException e) {
- Log.e(TAG, "subscribe failed: " + e);
- return false;
}
}
+ return 0;
+ }
+
+ /**
+ * Retrieve events
+ *
+ * @param reference of the last event previously returned. The function will return
+ * events following it.
+ * If 0 then all events will be returned.
+ * After the function call it will contain reference of the
+ * last returned event.
+ * @return events
+ */
+ public ConnectivityMetricsEvent[] getEvents(ConnectivityMetricsEvent.Reference reference) {
+ enforceDumpPermission();
+ long ref = reference.value;
+ if (VDBG) Log.v(TAG, "getEvents(" + ref + ")");
+
+ ConnectivityMetricsEvent[] result;
+ synchronized (mEvents) {
+ if (ref > mLastEventReference) {
+ Log.e(TAG, "Invalid reference");
+ reference.value = mLastEventReference;
+ return null;
+ }
+ if (ref < mLastEventReference - mEvents.size()) {
+ ref = mLastEventReference - mEvents.size();
+ }
+
+ int numEventsToSkip =
+ mEvents.size() // Total number of events
+ - (int)(mLastEventReference - ref); // Number of events to return
+
+ result = new ConnectivityMetricsEvent[mEvents.size() - numEventsToSkip];
+ int i = 0;
+ for (ConnectivityMetricsEvent e : mEvents) {
+ if (numEventsToSkip > 0) {
+ numEventsToSkip--;
+ } else {
+ result[i++] = e;
+ }
+ }
+ }
+
+ reference.value = mLastEventReference;
+
+ return result;
+ }
+
+ public boolean register(PendingIntent newEventsIntent) {
+ enforceDumpPermission();
+ if (VDBG) Log.v(TAG, "register(" + newEventsIntent + ")");
+
+ synchronized (mPendingIntents) {
+ if (mPendingIntents.remove(newEventsIntent)) {
+ Log.w(TAG, "Replacing registered pending intent");
+ }
+ mPendingIntents.add(newEventsIntent);
+ }
+
return true;
}
- public void unsubscribe(IConnectivityMetricsLoggerSubscriber subscriber) {
- enforceConnectivityInternalPermission();
- if (VDBG) Log.v(TAG, "unsubscribe");
- synchronized (mSubscribers) {
- IBinder.DeathRecipient dr = mSubscribers.remove(subscriber);
- if (dr == null) {
- Log.e(TAG, "subscriber is not subscribed");
- return;
+ public void unregister(PendingIntent newEventsIntent) {
+ enforceDumpPermission();
+ if (VDBG) Log.v(TAG, "unregister(" + newEventsIntent + ")");
+
+ synchronized (mPendingIntents) {
+ if (!mPendingIntents.remove(newEventsIntent)) {
+ Log.e(TAG, "Pending intent is not registered");
}
- subscriber.asBinder().unlinkToDeath(dr, 0);
}
}
};
diff --git a/services/core/java/com/android/server/connectivity/Tethering.java b/services/core/java/com/android/server/connectivity/Tethering.java
index da9c48a..2cba93fd 100644
--- a/services/core/java/com/android/server/connectivity/Tethering.java
+++ b/services/core/java/com/android/server/connectivity/Tethering.java
@@ -32,6 +32,7 @@
import android.content.res.Resources;
import android.hardware.usb.UsbManager;
import android.net.ConnectivityManager;
+import android.net.ConnectivityManager.NetworkCallback;
import android.net.INetworkStatsService;
import android.net.InterfaceConfiguration;
import android.net.LinkAddress;
@@ -40,6 +41,7 @@
import android.net.NetworkCapabilities;
import android.net.NetworkInfo;
import android.net.NetworkRequest;
+import android.net.NetworkState;
import android.net.NetworkUtils;
import android.net.RouteInfo;
import android.net.wifi.WifiManager;
@@ -88,7 +90,7 @@
*/
public class Tethering extends BaseNetworkObserver {
- private Context mContext;
+ private final Context mContext;
private final static String TAG = "Tethering";
private final static boolean DBG = false;
private final static boolean VDBG = false;
@@ -100,7 +102,7 @@
private Collection<Integer> mUpstreamIfaceTypes;
// used to synchronize public access to members
- private Object mPublicSync;
+ private final Object mPublicSync;
private static final Integer MOBILE_TYPE = new Integer(ConnectivityManager.TYPE_MOBILE);
private static final Integer HIPRI_TYPE = new Integer(ConnectivityManager.TYPE_MOBILE_HIPRI);
@@ -112,7 +114,7 @@
private final INetworkManagementService mNMService;
private final INetworkStatsService mStatsService;
- private Looper mLooper;
+ private final Looper mLooper;
private HashMap<String, TetherInterfaceSM> mIfaces; // all tethered/tetherable ifaces
@@ -143,7 +145,9 @@
private static final String DNS_DEFAULT_SERVER1 = "8.8.8.8";
private static final String DNS_DEFAULT_SERVER2 = "8.8.4.4";
- private StateMachine mTetherMasterSM;
+ private final StateMachine mTetherMasterSM;
+ private final UpstreamNetworkMonitor mUpstreamNetworkMonitor;
+ private String mCurrentUpstreamIface;
private Notification.Builder mTetheredNotificationBuilder;
private int mLastNotificationId;
@@ -167,6 +171,8 @@
mTetherMasterSM = new TetherMasterSM("TetherMaster", mLooper);
mTetherMasterSM.start();
+ mUpstreamNetworkMonitor = new UpstreamNetworkMonitor();
+
mStateReceiver = new StateReceiver();
IntentFilter filter = new IntentFilter();
filter.addAction(UsbManager.ACTION_USB_STATE);
@@ -505,7 +511,7 @@
};
// The following is necessary to avoid unmarshalling issues when sending the receiver
- // across proccesses.
+ // across processes.
Parcel parcel = Parcel.obtain();
rr.writeToParcel(parcel,0);
parcel.setDataPosition(0);
@@ -559,6 +565,7 @@
}
}
}
+
public int tether(String iface) {
if (DBG) Log.d(TAG, "Tethering " + iface);
TetherInterfaceSM sm = null;
@@ -1204,6 +1211,11 @@
Log.e(TAG, "Error Tethering: " + e.toString());
setLastError(ConnectivityManager.TETHER_ERROR_TETHER_IFACE_ERROR);
+ try {
+ mNMService.untetherInterface(mIfaceName);
+ } catch (Exception ee) {
+ Log.e(TAG, "Error untethering after failure!" + ee.toString());
+ }
transitionTo(mInitialState);
return;
}
@@ -1371,15 +1383,115 @@
}
+ /**
+ * A NetworkCallback class that relays information of interest to the
+ * tethering master state machine thread for subsequent processing.
+ */
+ class UpstreamNetworkCallback extends NetworkCallback {
+ @Override
+ public void onLinkPropertiesChanged(Network network, LinkProperties newLp) {
+ mTetherMasterSM.sendMessage(
+ TetherMasterSM.EVENT_UPSTREAM_LINKPROPERTIES_CHANGED,
+ new NetworkState(null, newLp, null, network, null, null));
+ }
+
+ @Override
+ public void onLost(Network network) {
+ mTetherMasterSM.sendMessage(TetherMasterSM.EVENT_UPSTREAM_LOST, network);
+ }
+ }
+
+ /**
+ * A class to centralize all the network and link properties information
+ * pertaining to the current and any potential upstream network.
+ *
+ * Calling #start() registers two callbacks: one to track the system default
+ * network and a second to specifically observe TYPE_MOBILE_DUN networks.
+ *
+ * The methods and data members of this class are only to be accessed and
+ * modified from the tethering master state machine thread. Any other
+ * access semantics would necessitate the addition of locking.
+ *
+ * TODO: Investigate whether more "upstream-specific" logic/functionality
+ * could/should be moved here.
+ */
+ class UpstreamNetworkMonitor {
+ final HashMap<Network, NetworkState> mNetworkMap = new HashMap();
+ NetworkCallback mDefaultNetworkCallback;
+ NetworkCallback mDunTetheringCallback;
+
+ void start() {
+ stop();
+
+ mDefaultNetworkCallback = new UpstreamNetworkCallback();
+ getConnectivityManager().registerDefaultNetworkCallback(mDefaultNetworkCallback);
+
+ final NetworkRequest dunTetheringRequest = new NetworkRequest.Builder()
+ .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
+ .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)
+ .addCapability(NetworkCapabilities.NET_CAPABILITY_DUN)
+ .build();
+ mDunTetheringCallback = new UpstreamNetworkCallback();
+ getConnectivityManager().registerNetworkCallback(
+ dunTetheringRequest, mDunTetheringCallback);
+ }
+
+ void stop() {
+ if (mDefaultNetworkCallback != null) {
+ getConnectivityManager().unregisterNetworkCallback(mDefaultNetworkCallback);
+ mDefaultNetworkCallback = null;
+ }
+
+ if (mDunTetheringCallback != null) {
+ getConnectivityManager().unregisterNetworkCallback(mDunTetheringCallback);
+ mDunTetheringCallback = null;
+ }
+
+ mNetworkMap.clear();
+ }
+
+ // Returns true if these updated LinkProperties pertain to the current
+ // upstream network interface, false otherwise (or if there is not
+ // currently any upstream tethering interface).
+ boolean processLinkPropertiesChanged(NetworkState networkState) {
+ if (networkState == null ||
+ networkState.network == null ||
+ networkState.linkProperties == null) {
+ return false;
+ }
+
+ mNetworkMap.put(networkState.network, networkState);
+
+ if (mCurrentUpstreamIface != null) {
+ for (String ifname : networkState.linkProperties.getAllInterfaceNames()) {
+ if (mCurrentUpstreamIface.equals(ifname)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ void processNetworkLost(Network network) {
+ if (network != null) {
+ mNetworkMap.remove(network);
+ }
+ }
+ }
+
class TetherMasterSM extends StateMachine {
// an interface SM has requested Tethering
- static final int CMD_TETHER_MODE_REQUESTED = 1;
+ static final int CMD_TETHER_MODE_REQUESTED = 1;
// an interface SM has unrequested Tethering
- static final int CMD_TETHER_MODE_UNREQUESTED = 2;
+ static final int CMD_TETHER_MODE_UNREQUESTED = 2;
// upstream connection change - do the right thing
- static final int CMD_UPSTREAM_CHANGED = 3;
+ static final int CMD_UPSTREAM_CHANGED = 3;
// we don't have a valid upstream conn, check again after a delay
- static final int CMD_RETRY_UPSTREAM = 4;
+ static final int CMD_RETRY_UPSTREAM = 4;
+ // Events from NetworkCallbacks that we process on the master state
+ // machine thread on behalf of the UpstreamNetworkMonitor.
+ static final int EVENT_UPSTREAM_LINKPROPERTIES_CHANGED = 5;
+ static final int EVENT_UPSTREAM_LOST = 6;
// This indicates what a timeout event relates to. A state that
// sends itself a delayed timeout event and handles incoming timeout events
@@ -1399,9 +1511,7 @@
private ArrayList<TetherInterfaceSM> mNotifyList;
private int mMobileApnReserved = ConnectivityManager.TYPE_NONE;
- private ConnectivityManager.NetworkCallback mMobileUpstreamCallback;
-
- private String mUpstreamIfaceName = null;
+ private NetworkCallback mMobileUpstreamCallback;
private static final int UPSTREAM_SETTLE_TIME_MS = 10000;
@@ -1430,8 +1540,6 @@
}
class TetherMasterUtilState extends State {
- protected final static boolean WAIT_FOR_NETWORK_TO_SETTLE = false;
-
@Override
public boolean processMessage(Message m) {
return false;
@@ -1461,27 +1569,27 @@
return false;
}
- NetworkRequest.Builder builder = new NetworkRequest.Builder()
+ final NetworkRequest.Builder builder = new NetworkRequest.Builder()
.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);
if (apnType == ConnectivityManager.TYPE_MOBILE_DUN) {
- builder.addCapability(NetworkCapabilities.NET_CAPABILITY_DUN)
- .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED);
+ builder.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)
+ .addCapability(NetworkCapabilities.NET_CAPABILITY_DUN);
} else {
builder.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
}
- NetworkRequest mobileUpstreamRequest = builder.build();
- // Other mechanisms notice network and interface changes and act upon them.
- // TODO, imminently: replace with a proper NetworkCallback-based scheme.
- //
+ final NetworkRequest mobileUpstreamRequest = builder.build();
+
+ // The UpstreamNetworkMonitor's callback will be notified.
+ // Therefore, to avoid duplicate notifications, we only register a no-op.
+ mMobileUpstreamCallback = new NetworkCallback();
+
// TODO: Change the timeout from 0 (no onUnavailable callback) to use some
// moderate callback time (once timeout callbacks are implemented). This might
// be useful for updating some UI. Additionally, we should definitely log a
- // message to aid in any subsequent debugging.
- mMobileUpstreamCallback = new ConnectivityManager.NetworkCallback();
+ // message to aid in any subsequent debugging
if (DBG) Log.d(TAG, "requesting mobile upstream network: " + mobileUpstreamRequest);
getConnectivityManager().requestNetwork(
mobileUpstreamRequest, mMobileUpstreamCallback, 0, apnType);
-
return true;
}
@@ -1513,6 +1621,7 @@
}
return true;
}
+
protected boolean turnOffMasterTetherSettings() {
try {
mNMService.stopTethering();
@@ -1606,34 +1715,41 @@
}
if (iface != null) {
- String[] dnsServers = mDefaultDnsServers;
- Collection<InetAddress> dnses = linkProperties.getDnsServers();
- if (dnses != null && !dnses.isEmpty()) {
- // TODO: remove this invocation of NetworkUtils.makeStrings().
- dnsServers = NetworkUtils.makeStrings(dnses);
+ Network network = getConnectivityManager().getNetworkForType(upType);
+ if (network == null) {
+ Log.e(TAG, "No Network for upstream type " + upType + "!");
}
- try {
- Network network = getConnectivityManager().getNetworkForType(upType);
- if (network == null) {
- Log.e(TAG, "No Network for upstream type " + upType + "!");
- }
- if (VDBG) {
- Log.d(TAG, "Setting DNS forwarders: Network=" + network +
- ", dnsServers=" + Arrays.toString(dnsServers));
- }
- mNMService.setDnsForwarders(network, dnsServers);
- } catch (Exception e) {
- Log.e(TAG, "Setting DNS forwarders failed!");
- transitionTo(mSetDnsForwardersErrorState);
- }
+ setDnsForwarders(network, linkProperties);
}
}
notifyTetheredOfNewUpstreamIface(iface);
}
+ protected void setDnsForwarders(final Network network, final LinkProperties lp) {
+ String[] dnsServers = mDefaultDnsServers;
+ final Collection<InetAddress> dnses = lp.getDnsServers();
+ // TODO: Properly support the absence of DNS servers.
+ if (dnses != null && !dnses.isEmpty()) {
+ // TODO: remove this invocation of NetworkUtils.makeStrings().
+ dnsServers = NetworkUtils.makeStrings(dnses);
+ }
+ if (VDBG) {
+ Log.d(TAG, "Setting DNS forwarders: Network=" + network +
+ ", dnsServers=" + Arrays.toString(dnsServers));
+ }
+ try {
+ mNMService.setDnsForwarders(network, dnsServers);
+ } catch (Exception e) {
+ // TODO: Investigate how this can fail and what exactly
+ // happens if/when such failures occur.
+ Log.e(TAG, "Setting DNS forwarders failed!");
+ transitionTo(mSetDnsForwardersErrorState);
+ }
+ }
+
protected void notifyTetheredOfNewUpstreamIface(String ifaceName) {
if (DBG) Log.d(TAG, "notifying tethered with iface =" + ifaceName);
- mUpstreamIfaceName = ifaceName;
+ mCurrentUpstreamIface = ifaceName;
for (TetherInterfaceSM sm : mNotifyList) {
sm.sendMessage(TetherInterfaceSM.CMD_TETHER_CONNECTION_CHANGED,
ifaceName);
@@ -1772,20 +1888,23 @@
}
class TetherModeAliveState extends TetherMasterUtilState {
- boolean mTryCell = !WAIT_FOR_NETWORK_TO_SETTLE;
+ boolean mTryCell = true;
@Override
public void enter() {
+ // TODO: examine if we should check the return value.
turnOnMasterTetherSettings(); // may transition us out
startListeningForSimChanges();
+ mUpstreamNetworkMonitor.start();
- mTryCell = !WAIT_FOR_NETWORK_TO_SETTLE; // better try something first pass
- // or crazy tests cases will fail
+ mTryCell = true; // better try something first pass or crazy tests cases will fail
chooseUpstreamType(mTryCell);
mTryCell = !mTryCell;
}
@Override
public void exit() {
+ // TODO: examine if we should check the return value.
turnOffUpstreamMobileConnection();
+ mUpstreamNetworkMonitor.stop();
stopListeningForSimChanges();
notifyTetheredOfNewUpstreamIface(null);
}
@@ -1799,7 +1918,7 @@
if (VDBG) Log.d(TAG, "Tether Mode requested by " + who);
mNotifyList.add(who);
who.sendMessage(TetherInterfaceSM.CMD_TETHER_CONNECTION_CHANGED,
- mUpstreamIfaceName);
+ mCurrentUpstreamIface);
break;
case CMD_TETHER_MODE_UNREQUESTED:
who = (TetherInterfaceSM)message.obj;
@@ -1823,7 +1942,7 @@
break;
case CMD_UPSTREAM_CHANGED:
// need to try DUN immediately if Wifi goes down
- mTryCell = !WAIT_FOR_NETWORK_TO_SETTLE;
+ mTryCell = true;
chooseUpstreamType(mTryCell);
mTryCell = !mTryCell;
break;
@@ -1831,6 +1950,24 @@
chooseUpstreamType(mTryCell);
mTryCell = !mTryCell;
break;
+ case EVENT_UPSTREAM_LINKPROPERTIES_CHANGED:
+ NetworkState state = (NetworkState) message.obj;
+ if (mUpstreamNetworkMonitor.processLinkPropertiesChanged(state)) {
+ setDnsForwarders(state.network, state.linkProperties);
+ } else if (mCurrentUpstreamIface == null) {
+ // If we have no upstream interface, try to run through upstream
+ // selection again. If, for example, IPv4 connectivity has shown up
+ // after IPv6 (e.g., 464xlat became available) we want the chance to
+ // notice and act accordingly.
+ chooseUpstreamType(false);
+ }
+ break;
+ case EVENT_UPSTREAM_LOST:
+ // TODO: Re-evaluate possible upstreams. Currently upstream reevaluation
+ // is triggered via received CONNECTIVITY_ACTION broadcasts that result
+ // in being passed a TetherMasterSM.CMD_UPSTREAM_CHANGED.
+ mUpstreamNetworkMonitor.processNetworkLost((Network) message.obj);
+ break;
default:
retValue = false;
break;
diff --git a/services/core/java/com/android/server/content/ContentService.java b/services/core/java/com/android/server/content/ContentService.java
index 28170f2..7f7ea9d 100644
--- a/services/core/java/com/android/server/content/ContentService.java
+++ b/services/core/java/com/android/server/content/ContentService.java
@@ -26,9 +26,9 @@
import android.content.ContentResolver;
import android.content.Context;
import android.content.IContentService;
+import android.content.ISyncStatusObserver;
import android.content.Intent;
import android.content.IntentFilter;
-import android.content.ISyncStatusObserver;
import android.content.PeriodicSync;
import android.content.SyncAdapterType;
import android.content.SyncInfo;
@@ -58,18 +58,15 @@
import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.IndentingPrintWriter;
-import com.android.internal.util.Preconditions;
import com.android.server.LocalServices;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.security.InvalidParameterException;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
-import java.util.Objects;
/**
* {@hide}
@@ -1030,14 +1027,16 @@
if (uri != null) {
for (int i = 0; i < packageCache.size();) {
- final Uri key = packageCache.keyAt(i).second;
- if (Objects.equals(key, uri)) {
+ final Pair<String, Uri> key = packageCache.keyAt(i);
+ if (key.second != null && key.second.toString().startsWith(uri.toString())) {
+ Slog.d(TAG, "Invalidating cache for key " + key);
packageCache.removeAt(i);
} else {
i++;
}
}
} else {
+ Slog.d(TAG, "Invalidating cache for package " + providerPackageName);
packageCache.clear();
}
}
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index 1ed7070..8f8afd5 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -103,7 +103,6 @@
private static final float TYPICAL_PROXIMITY_THRESHOLD = 5.0f;
// Brightness animation ramp rate in brightness units per second.
- private static final int BRIGHTNESS_RAMP_RATE_FAST = 200;
private static final int BRIGHTNESS_RAMP_RATE_SLOW = 40;
private static final int REPORTED_TO_POLICY_SCREEN_OFF = 0;
@@ -244,6 +243,9 @@
private boolean mAppliedDimming;
private boolean mAppliedLowPower;
+ // Brightness ramp rate fast.
+ private final int mBrightnessRampRateFast;
+
// The controller for the automatic brightness level.
private AutomaticBrightnessController mAutomaticBrightnessController;
@@ -303,6 +305,9 @@
mAllowAutoBrightnessWhileDozingConfig = resources.getBoolean(
com.android.internal.R.bool.config_allowAutoBrightnessWhileDozing);
+ mBrightnessRampRateFast = resources.getInteger(
+ com.android.internal.R.integer.config_brightness_ramp_rate_fast);
+
int lightSensorRate = resources.getInteger(
com.android.internal.R.integer.config_autoBrightnessLightSensorRate);
long brighteningLightDebounce = resources.getInteger(
@@ -698,7 +703,7 @@
if (!mPendingScreenOff) {
if (state == Display.STATE_ON || state == Display.STATE_DOZE) {
animateScreenBrightness(brightness,
- slowChange ? BRIGHTNESS_RAMP_RATE_SLOW : BRIGHTNESS_RAMP_RATE_FAST);
+ slowChange ? BRIGHTNESS_RAMP_RATE_SLOW : mBrightnessRampRateFast);
} else {
animateScreenBrightness(brightness, 0);
}
diff --git a/services/core/java/com/android/server/dreams/DreamManagerService.java b/services/core/java/com/android/server/dreams/DreamManagerService.java
index 8813a61..1f6616e 100644
--- a/services/core/java/com/android/server/dreams/DreamManagerService.java
+++ b/services/core/java/com/android/server/dreams/DreamManagerService.java
@@ -335,7 +335,8 @@
private ServiceInfo getServiceInfo(ComponentName name) {
try {
- return name != null ? mContext.getPackageManager().getServiceInfo(name, 0) : null;
+ return name != null ? mContext.getPackageManager().getServiceInfo(name,
+ PackageManager.MATCH_DEBUG_TRIAGED_MISSING) : null;
} catch (NameNotFoundException e) {
return null;
}
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
index a36e671..69c012e 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
@@ -165,15 +165,13 @@
@ServiceThreadOnly
protected void onStandby(boolean initiatedByCec, int standbyAction) {
assertRunOnServiceThread();
- if (!mService.isControlEnabled() || initiatedByCec) {
+ if (!mService.isControlEnabled() || initiatedByCec || !mAutoTvOff) {
return;
}
switch (standbyAction) {
case HdmiControlService.STANDBY_SCREEN_OFF:
- if (mAutoTvOff) {
- mService.sendCecCommand(
- HdmiCecMessageBuilder.buildStandby(mAddress, Constants.ADDR_TV));
- }
+ mService.sendCecCommand(
+ HdmiCecMessageBuilder.buildStandby(mAddress, Constants.ADDR_TV));
break;
case HdmiControlService.STANDBY_SHUTDOWN:
// ACTION_SHUTDOWN is taken as a signal to power off all the devices.
diff --git a/services/core/java/com/android/server/hdmi/HdmiLogger.java b/services/core/java/com/android/server/hdmi/HdmiLogger.java
index 0b201710..537df81 100644
--- a/services/core/java/com/android/server/hdmi/HdmiLogger.java
+++ b/services/core/java/com/android/server/hdmi/HdmiLogger.java
@@ -21,6 +21,7 @@
import android.os.SystemClock;
import android.util.Pair;
import android.util.Slog;
+import android.util.Log;
import java.util.HashMap;
@@ -42,6 +43,7 @@
// Logging duration for same error message.
private static final long ERROR_LOG_DURATTION_MILLIS = 20 * 1000; // 20s
+ private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
private static final boolean IS_USER_BUILD = "user".equals(Build.TYPE);
private static final ThreadLocal<HdmiLogger> sLogger = new ThreadLocal<>();
@@ -83,10 +85,9 @@
}
private void debugInternal(String logMessage) {
- if (true || IS_USER_BUILD) {
- return;
+ if (DEBUG) {
+ Slog.d(TAG, logMessage);
}
- Slog.d(TAG, logMessage);
}
private static final String toLogString(String logMessage, Object[] objs) {
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index 3c04b78..e73beaa 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -948,7 +948,7 @@
// Must be called on handler.
private void showMissingKeyboardLayoutNotification(InputDevice device) {
if (!mKeyboardLayoutNotificationShown) {
- final Intent intent = new Intent(Settings.ACTION_INPUT_METHOD_SETTINGS);
+ final Intent intent = new Intent(Settings.ACTION_HARD_KEYBOARD_SETTINGS);
if (device != null) {
intent.putExtra(Settings.EXTRA_INPUT_DEVICE_IDENTIFIER, device.getIdentifier());
}
diff --git a/services/core/java/com/android/server/job/JobSchedulerService.java b/services/core/java/com/android/server/job/JobSchedulerService.java
index 6b00f5f..fa8620f 100644
--- a/services/core/java/com/android/server/job/JobSchedulerService.java
+++ b/services/core/java/com/android/server/job/JobSchedulerService.java
@@ -58,8 +58,8 @@
import android.util.TimeUtils;
import com.android.internal.app.IBatteryStats;
+import com.android.internal.app.procstats.ProcessStats;
import com.android.internal.util.ArrayUtils;
-import com.android.internal.app.ProcessStats;
import com.android.server.DeviceIdleController;
import com.android.server.LocalServices;
import com.android.server.job.JobStore.JobStatusFunctor;
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index 9b92e4f..612bae2 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -49,7 +49,9 @@
import static android.net.NetworkPolicyManager.POLICY_NONE;
import static android.net.NetworkPolicyManager.POLICY_REJECT_METERED_BACKGROUND;
import static android.net.NetworkPolicyManager.RULE_ALLOW_ALL;
+import static android.net.NetworkPolicyManager.RULE_ALLOW_METERED;
import static android.net.NetworkPolicyManager.RULE_REJECT_METERED;
+import static android.net.NetworkPolicyManager.RULE_TEMPORARY_ALLOW_METERED;
import static android.net.NetworkPolicyManager.RULE_UNKNOWN;
import static android.net.NetworkPolicyManager.computeLastCycleBoundary;
import static android.net.NetworkTemplate.MATCH_MOBILE_3G_LOWER;
@@ -687,7 +689,7 @@
// global background data policy
if (LOGV) Slog.v(TAG, "ACTION_PACKAGE_ADDED for uid=" + uid);
synchronized (mRulesLock) {
- updateRestrictDataRulesForUidLocked(uid);
+ updateRestrictionRulesForUidLocked(uid);
}
}
}
@@ -705,7 +707,7 @@
if (LOGV) Slog.v(TAG, "ACTION_UID_REMOVED for uid=" + uid);
synchronized (mRulesLock) {
mUidPolicy.delete(uid);
- updateRestrictDataRulesForUidLocked(uid);
+ updateRuleForRestrictBackgroundLocked(uid);
writePolicyLocked();
}
}
@@ -1678,7 +1680,7 @@
mUidPolicy.put(uid, policy);
// uid policy changed, recompute rules and persist policy.
- updateRestrictDataRulesForUidLocked(uid);
+ updateRuleForRestrictBackgroundLocked(uid);
if (persist) {
writePolicyLocked();
}
@@ -1729,7 +1731,7 @@
if (wlUids.length > 0) {
for (int uid : wlUids) {
- removeRestrictBackgroundWhitelistedUidLocked(uid, false);
+ removeRestrictBackgroundWhitelistedUidLocked(uid, false, false);
}
writePolicy = true;
}
@@ -1896,10 +1898,12 @@
try {
maybeRefreshTrustedTime();
synchronized (mRulesLock) {
- mRestrictBackground = restrictBackground;
- updateRulesForRestrictDataLocked();
- updateNotificationsLocked();
- writePolicyLocked();
+ if (restrictBackground == mRestrictBackground) {
+ // Ideally, UI should never allow this scenario...
+ Slog.w(TAG, "setRestrictBackground: already " + restrictBackground);
+ return;
+ }
+ setRestrictBackgroundLocked(restrictBackground);
}
} finally {
@@ -1910,17 +1914,40 @@
.sendToTarget();
}
+ private void setRestrictBackgroundLocked(boolean 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();
+ 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.
+ return;
+ }
+ } catch (RemoteException e) {
+ // ignored; service lives in system_server
+ }
+ updateNotificationsLocked();
+ writePolicyLocked();
+ }
+
@Override
public void addRestrictBackgroundWhitelistedUid(int uid) {
mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
- if (!isUidValidForRules(uid)) return;
- final boolean changed;
+ final boolean oldStatus;
+ final boolean needFirewallRules;
synchronized (mRulesLock) {
- final boolean oldStatus = mRestrictBackgroundWhitelistUids.get(uid);
+ oldStatus = mRestrictBackgroundWhitelistUids.get(uid);
if (oldStatus) {
if (LOGD) Slog.d(TAG, "uid " + uid + " is already whitelisted");
return;
}
+ needFirewallRules = isUidValidForWhitelistRules(uid);
Slog.i(TAG, "adding uid " + uid + " to restrict background whitelist");
mRestrictBackgroundWhitelistUids.append(uid, true);
if (mDefaultRestrictBackgroundWhitelistUids.get(uid)
@@ -1929,13 +1956,14 @@
+ " from revoked restrict background whitelist");
mRestrictBackgroundWhitelistRevokedUids.delete(uid);
}
- changed = mRestrictBackground && !oldStatus;
- if (changed && hasInternetPermissions(uid)) {
- setUidNetworkRules(uid, false);
+ if (needFirewallRules) {
+ // Only update firewall rules if necessary...
+ updateRuleForRestrictBackgroundLocked(uid);
}
+ // ...but always persists the whitelist request.
writePolicyLocked();
}
- if (changed) {
+ if (mRestrictBackground && !oldStatus && needFirewallRules) {
mHandler.obtainMessage(MSG_RESTRICT_BACKGROUND_WHITELIST_CHANGED, uid, 0)
.sendToTarget();
}
@@ -1944,10 +1972,9 @@
@Override
public void removeRestrictBackgroundWhitelistedUid(int uid) {
mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
- if (!isUidValidForRules(uid)) return;
final boolean changed;
synchronized (mRulesLock) {
- changed = removeRestrictBackgroundWhitelistedUidLocked(uid, true);
+ changed = removeRestrictBackgroundWhitelistedUidLocked(uid, false, true);
}
if (changed) {
mHandler.obtainMessage(MSG_RESTRICT_BACKGROUND_WHITELIST_CHANGED, uid, 0)
@@ -1955,14 +1982,19 @@
}
}
- private boolean removeRestrictBackgroundWhitelistedUidLocked(int uid, boolean updateNow) {
+ /**
+ * Removes a uid from the restricted background whitelist, returning whether its current
+ * {@link ConnectivityManager.RestrictBackgroundStatus} changed.
+ */
+ private boolean removeRestrictBackgroundWhitelistedUidLocked(int uid, boolean uidDeleted,
+ boolean updateNow) {
final boolean oldStatus = mRestrictBackgroundWhitelistUids.get(uid);
if (!oldStatus) {
if (LOGD) Slog.d(TAG, "uid " + uid + " was not whitelisted before");
return false;
}
+ final boolean needFirewallRules = uidDeleted || isUidValidForWhitelistRules(uid);
Slog.i(TAG, "removing uid " + uid + " from restrict background whitelist");
- final boolean changed = mRestrictBackground && oldStatus;
mRestrictBackgroundWhitelistUids.delete(uid);
if (mDefaultRestrictBackgroundWhitelistUids.get(uid)
&& !mRestrictBackgroundWhitelistRevokedUids.get(uid)) {
@@ -1970,13 +2002,17 @@
+ " to revoked restrict background whitelist");
mRestrictBackgroundWhitelistRevokedUids.append(uid, true);
}
+ if (needFirewallRules) {
+ // Only update firewall rules if necessary...
+ updateRuleForRestrictBackgroundLocked(uid, uidDeleted);
+ }
if (updateNow) {
- if (changed && hasInternetPermissions(uid)) {
- setUidNetworkRules(uid, true);
- }
+ // ...but always persists the whitelist request.
writePolicyLocked();
}
- return changed;
+ // Status only changes if Data Saver is turned on (otherwise it is DISABLED, even if the
+ // app was whitelisted before).
+ return mRestrictBackground && needFirewallRules;
}
@Override
@@ -2268,11 +2304,16 @@
final int state = mUidState.get(uid, ActivityManager.PROCESS_STATE_CACHED_EMPTY);
fout.print(" state=");
fout.print(state);
- fout.print(state <= ActivityManager.PROCESS_STATE_TOP ? " (fg)" : " (bg)");
+ if (state <= ActivityManager.PROCESS_STATE_TOP) {
+ fout.print(" (fg)");
+ } else {
+ fout.print(state <= ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE
+ ? " (fg svc)" : " (bg)");
+ }
final int rule = mUidRules.get(uid, RULE_UNKNOWN);
fout.print(" rule=");
- fout.print(DebugUtils.valueToString(NetworkPolicyManager.class, "RULE_", rule));
+ fout.print(ruleToString(rule));
fout.println();
}
@@ -2280,6 +2321,10 @@
}
}
+ private String ruleToString(int rule) {
+ return DebugUtils.valueToString(NetworkPolicyManager.class, "RULE_", rule);
+ }
+
@Override
public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,
String[] args, ResultReceiver resultReceiver) throws RemoteException {
@@ -2296,57 +2341,80 @@
}
}
- boolean isUidForegroundLocked(int uid) {
+ private boolean isUidForegroundLocked(int uid) {
+ return isUidStateForegroundLocked(
+ mUidState.get(uid, ActivityManager.PROCESS_STATE_CACHED_EMPTY));
+ }
+
+ private boolean isUidForegroundOnRestrictBackgroundLocked(int uid) {
+ final int procState = mUidState.get(uid, ActivityManager.PROCESS_STATE_CACHED_EMPTY);
+ return isProcStateAllowedWhileOnRestrictBackgroundLocked(procState);
+ }
+
+ private boolean isUidStateForegroundLocked(int state) {
// only really in foreground when screen is also on
- return mScreenOn && mUidState.get(uid, ActivityManager.PROCESS_STATE_CACHED_EMPTY)
- <= ActivityManager.PROCESS_STATE_TOP;
+ return mScreenOn && state <= ActivityManager.PROCESS_STATE_TOP;
}
/**
* Process state of UID changed; if needed, will trigger
- * {@link #updateRestrictDataRulesForUidLocked(int)}.
+ * {@link #updateRuleForRestrictBackgroundLocked(int)}.
*/
- void updateUidStateLocked(int uid, int uidState) {
+ private void updateUidStateLocked(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);
- updateRulesForUidStateChangeLocked(uid, oldUidState, uidState);
+ updateRestrictBackgroundRulesOnUidStatusChangedLocked(uid, oldUidState, uidState);
if (isProcStateAllowedWhileIdleOrPowerSaveMode(oldUidState)
!= isProcStateAllowedWhileIdleOrPowerSaveMode(uidState) ) {
if (mDeviceIdleMode) {
updateRuleForDeviceIdleLocked(uid);
}
if (mRestrictPower) {
- updateRulesForRestrictPowerLocked(uid);
+ updateRuleForRestrictPowerLocked(uid);
}
}
+ updateNetworkStats(uid, isUidStateForegroundLocked(uidState));
}
}
- void removeUidStateLocked(int uid) {
+ private void removeUidStateLocked(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) {
- updateRulesForUidStateChangeLocked(uid, oldUidState,
+ updateRestrictBackgroundRulesOnUidStatusChangedLocked(uid, oldUidState,
ActivityManager.PROCESS_STATE_CACHED_EMPTY);
if (mDeviceIdleMode) {
updateRuleForDeviceIdleLocked(uid);
}
if (mRestrictPower) {
- updateRulesForRestrictPowerLocked(uid);
+ updateRuleForRestrictPowerLocked(uid);
}
+ updateNetworkStats(uid, false);
}
}
}
- void updateRulesForUidStateChangeLocked(int uid, int oldUidState, int newUidState) {
- final boolean oldForeground = oldUidState <= ActivityManager.PROCESS_STATE_TOP;
- final boolean newForeground = newUidState <= ActivityManager.PROCESS_STATE_TOP;
+ // adjust stats accounting based on foreground status
+ private void updateNetworkStats(int uid, boolean uidForeground) {
+ try {
+ mNetworkStats.setUidForeground(uid, uidForeground);
+ } catch (RemoteException e) {
+ // ignored; service lives in system_server
+ }
+ }
+
+ private void updateRestrictBackgroundRulesOnUidStatusChangedLocked(int uid, int oldUidState,
+ int newUidState) {
+ final boolean oldForeground =
+ isProcStateAllowedWhileOnRestrictBackgroundLocked(oldUidState);
+ final boolean newForeground =
+ isProcStateAllowedWhileOnRestrictBackgroundLocked(newUidState);
if (oldForeground != newForeground) {
- updateRestrictDataRulesForUidLocked(uid);
+ updateRuleForRestrictBackgroundLocked(uid);
}
}
@@ -2368,9 +2436,9 @@
// 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_TOP) {
+ if (mUidState.valueAt(i) <= ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE) {
final int uid = mUidState.keyAt(i);
- updateRestrictDataRulesForUidLocked(uid);
+ updateRestrictionRulesForUidLocked(uid);
}
}
}
@@ -2379,12 +2447,16 @@
return procState <= ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE;
}
+ static boolean isProcStateAllowedWhileOnRestrictBackgroundLocked(int procState) {
+ return procState <= ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE;
+ }
+
void updateRulesForRestrictPowerLocked() {
updateRulesForWhitelistedPowerSaveLocked(mRestrictPower, FIREWALL_CHAIN_POWERSAVE,
mUidFirewallPowerSaveRules);
}
- void updateRulesForRestrictPowerLocked(int uid) {
+ void updateRuleForRestrictPowerLocked(int uid) {
updateRulesForWhitelistedPowerSaveLocked(uid, mRestrictPower, FIREWALL_CHAIN_POWERSAVE);
}
@@ -2397,8 +2469,8 @@
updateRulesForWhitelistedPowerSaveLocked(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.
+ // 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,
SparseIntArray rules) {
if (enabled) {
@@ -2433,8 +2505,8 @@
enableFirewallChainLocked(chain, enabled);
}
- // NOTE: since both fw_dozable and fw_powersave uses the same map (mPowerSaveTempWhitelistAppIds)
- // for whitelisting, we can reuse their logic in this method.
+ // 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) {
if (enabled) {
int appId = UserHandle.getAppId(uid);
@@ -2452,7 +2524,6 @@
uidRules.clear();
// Fully update the app idle firewall chain.
- final IPackageManager ipm = AppGlobals.getPackageManager();
final List<UserInfo> users = mUserManager.getUsers();
for (int ui = users.size() - 1; ui >= 0; ui--) {
UserInfo user = users.get(ui);
@@ -2473,7 +2544,7 @@
}
void updateRuleForAppIdleLocked(int uid) {
- if (!isUidValidForRules(uid)) return;
+ if (!isUidValidForBlacklistRules(uid)) return;
int appId = UserHandle.getAppId(uid);
if (!mPowerSaveTempWhitelistAppIds.get(appId) && isUidIdle(uid)) {
@@ -2499,7 +2570,8 @@
updateRulesForDeviceIdleLocked();
updateRulesForAppIdleLocked();
updateRulesForRestrictPowerLocked();
- updateRulesForRestrictDataLocked();
+ updateRulesForRestrictBackgroundLocked();
+ setRestrictBackgroundLocked(mRestrictBackground);
// If the set of restricted networks may have changed, re-evaluate those.
if (restrictedNetworksChanged) {
@@ -2513,7 +2585,7 @@
}
}
- private void updateRulesForRestrictDataLocked() {
+ private void updateRulesForRestrictBackgroundLocked() {
final PackageManager pm = mContext.getPackageManager();
// update rules for all installed applications
@@ -2530,13 +2602,9 @@
for (int j = 0; j < appsSize; j++) {
final ApplicationInfo app = apps.get(j);
final int uid = UserHandle.getUid(user.id, app.uid);
- updateRestrictDataRulesForUidLocked(uid);
+ updateRuleForRestrictBackgroundLocked(uid);
}
}
-
- // limit data usage for some internal system services
- updateRestrictDataRulesForUidLocked(android.os.Process.MEDIA_UID);
- updateRestrictDataRulesForUidLocked(android.os.Process.DRM_UID);
}
private void updateRulesForTempWhitelistChangeLocked() {
@@ -2548,21 +2616,27 @@
int uid = UserHandle.getUid(user.id, appId);
updateRuleForAppIdleLocked(uid);
updateRuleForDeviceIdleLocked(uid);
- updateRulesForRestrictPowerLocked(uid);
+ updateRuleForRestrictPowerLocked(uid);
}
}
}
- private static boolean isUidValidForRules(int uid) {
+ // TODO: the MEDIA / DRM restriction might not be needed anymore, in which case both
+ // methods below could be merged into a isUidValidForRules() method.
+ private boolean isUidValidForBlacklistRules(int uid) {
// allow rules on specific system services, and any apps
if (uid == android.os.Process.MEDIA_UID || uid == android.os.Process.DRM_UID
- || UserHandle.isApp(uid)) {
+ || (UserHandle.isApp(uid) && hasInternetPermissions(uid))) {
return true;
}
return false;
}
+ private boolean isUidValidForWhitelistRules(int uid) {
+ return UserHandle.isApp(uid) && hasInternetPermissions(uid);
+ }
+
private boolean isUidIdle(int uid) {
final String[] packages = mContext.getPackageManager().getPackagesForUid(uid);
final int userId = UserHandle.getUserId(uid);
@@ -2594,32 +2668,99 @@
}
/**
- * Applies network rules to bandwidth controllers based on uid policy.
+ * Applies network rules to bandwidth and firewall controllers based on uid policy.
*
- * @param uid The uid for which to apply the latest policy
+ * <p>There are currently 2 types of restriction rules:
+ * <ul>
+ * <li>Battery Saver Mode (also referred as power save).
+ * <li>Data Saver Mode (formerly known as restrict background data).
+ * </ul>
*/
- private void updateRestrictDataRulesForUidLocked(int uid) {
- if (!isUidValidForRules(uid) || !hasInternetPermissions(uid)) return;
+ private void updateRestrictionRulesForUidLocked(int uid) {
+ updateRuleForRestrictPowerLocked(uid);
+ updateRuleForRestrictBackgroundLocked(uid);
+ }
+
+ /**
+ * Applies network rules to bandwidth controllers based on process state and user-defined
+ * restrictions (blacklist / whitelist).
+ *
+ * <p>
+ * {@code netd} defines 3 firewall chains that govern whether an app has access to metered
+ * networks:
+ * <ul>
+ * <li>@{code bw_penalty_box}: UIDs added to this chain do not have access (blacklist).
+ * <li>@{code bw_happy_box}: UIDs added to this chain have access (whitelist), unless they're
+ * also blacklisted.
+ * <li>@{code bw_data_saver}: when enabled (through {@link #setRestrictBackground(boolean)}),
+ * no UIDs other those whitelisted will have access.
+ * <ul>
+ *
+ * <p>The @{code bw_penalty_box} and @{code bw_happy_box} are primarily managed through the
+ * {@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 #updateRuleForRestrictBackgroundLocked(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:
+ *
+ * <ul>
+ * <li>When Data Saver mode is on, the foreground app should be temporarily added to
+ * {@code bw_happy_box} before the @{code bw_data_saver} chain is enabled.
+ * <li>If the foreground app is blacklisted by the user, it should be temporarily removed from
+ * {@code bw_penalty_box}.
+ * <li>When the app leaves foreground state, the temporary changes above should be reverted.
+ * </ul>
+ *
+ * <p>For optimization, the rules are only applied on user apps that have internet access
+ * permission, since there is no need to change the {@code iptables} rule if the app does not
+ * have permission to use the internet.
+ *
+ * <p>The {@link #mUidRules} map is used to define the transtion of states of an UID.
+ */
+ private void updateRuleForRestrictBackgroundLocked(int uid) {
+ updateRuleForRestrictBackgroundLocked(uid, false);
+ }
+
+ /**
+ * Overloaded version of {@link #updateRuleForRestrictBackgroundLocked(int)} called when an
+ * app is removed - it ignores the UID validity check.
+ */
+ private void updateRuleForRestrictBackgroundLocked(int uid, boolean uidDeleted) {
+ if (!uidDeleted && !isUidValidForWhitelistRules(uid)) {
+ if (LOGD) Slog.d(TAG, "no need to update restrict data rules for uid " + uid);
+ return;
+ }
final int uidPolicy = mUidPolicy.get(uid, POLICY_NONE);
- final boolean uidForeground = isUidForegroundLocked(uid);
+ final boolean isForeground = isUidForegroundOnRestrictBackgroundLocked(uid);
+ final boolean isBlacklisted = (uidPolicy & POLICY_REJECT_METERED_BACKGROUND) != 0;
+ final boolean isWhitelisted = mRestrictBackgroundWhitelistUids.get(uid);
- // Derive active rules based on policy and active state
int newRule = RULE_ALLOW_ALL;
+ final int oldRule = mUidRules.get(uid);
- if (!uidForeground) {
- // If the app is not in foreground, reject access if:
- // - app is blacklisted by policy or
- // - data saver mode is and app is not whitelisted
- if (((uidPolicy & POLICY_REJECT_METERED_BACKGROUND) != 0)
- || (mRestrictBackground && !mRestrictBackgroundWhitelistUids.get(uid))) {
+ // First step: define the new rule based on user restrictions and foreground state.
+ if (isForeground) {
+ if (isBlacklisted || (mRestrictBackground && !isWhitelisted)) {
+ newRule = RULE_TEMPORARY_ALLOW_METERED;
+ }
+ } else {
+ if (isBlacklisted) {
newRule = RULE_REJECT_METERED;
+ } else if (isWhitelisted) {
+ newRule = RULE_ALLOW_METERED;
}
}
- final int oldRule = mUidRules.get(uid);
- if (LOGV) Log.v(TAG, "updateBandwithControllerRulesForUidLocked(" + uid + "): oldRule = "
- + oldRule + ", newRule = " + newRule);
+ if (LOGV) {
+ Log.v(TAG, "updateRuleForRestrictBackgroundLocked(" + uid + "):"
+ + " isForeground=" +isForeground + ", isBlacklisted: " + isBlacklisted
+ + ", isWhitelisted: " + isWhitelisted + ", newRule: " + ruleToString(newRule)
+ + ", oldRule: " + ruleToString(oldRule));
+ }
+
if (newRule == RULE_ALLOW_ALL) {
mUidRules.delete(uid);
@@ -2627,20 +2768,55 @@
mUidRules.put(uid, newRule);
}
- final boolean rejectMetered = (newRule == RULE_REJECT_METERED);
- setUidNetworkRules(uid, rejectMetered);
+ // Second step: apply bw changes based on change of state.
+ if (newRule != oldRule) {
+ if (newRule == RULE_TEMPORARY_ALLOW_METERED) {
+ // Temporarily whitelist foreground app, removing from blacklist if necessary
+ // (since bw_penalty_box prevails over bw_happy_box).
- // dispatch changed rule to existing listeners
- if (oldRule != newRule) {
+ setMeteredNetworkWhitelist(uid, true);
+ // TODO: if statement below is used to avoid an unnecessary call to netd / iptables,
+ // but ideally it should be just:
+ // setMeteredNetworkBlacklist(uid, isBlacklisted);
+ if (isBlacklisted) {
+ setMeteredNetworkBlacklist(uid, false);
+ }
+ } else if (oldRule == RULE_TEMPORARY_ALLOW_METERED) {
+ // Remove temporary whitelist from app that is not on foreground anymore.
+
+ // TODO: if statements below are used to avoid unnecessary calls to netd / iptables,
+ // but ideally they should be just:
+ // setMeteredNetworkWhitelist(uid, isWhitelisted);
+ // setMeteredNetworkBlacklist(uid, isBlacklisted);
+ if (!isWhitelisted) {
+ setMeteredNetworkWhitelist(uid, false);
+ }
+ if (isBlacklisted) {
+ setMeteredNetworkBlacklist(uid, true);
+ }
+ } else if (newRule == RULE_REJECT_METERED || oldRule == RULE_REJECT_METERED) {
+ // Flip state because app was explicitly added or removed to blacklist.
+ setMeteredNetworkBlacklist(uid, isBlacklisted);
+ if (oldRule == RULE_REJECT_METERED && isWhitelisted) {
+ // Since blacklist prevails over whitelist, we need to handle the special case
+ // where app is whitelisted and blacklisted at the same time (although such
+ // scenario should be blocked by the UI), then blacklist is removed.
+ setMeteredNetworkWhitelist(uid, isWhitelisted);
+ }
+ } else if (newRule == RULE_ALLOW_METERED || oldRule == RULE_ALLOW_METERED) {
+ // Flip state because app was explicitly added or removed to whitelist.
+ setMeteredNetworkWhitelist(uid, isWhitelisted);
+ } else {
+ // All scenarios should have been covered above
+ Log.wtf(TAG, "Unexpected change of state for " + uid
+ + ": foreground=" + isForeground + ", whitelisted=" + isWhitelisted
+ + ", blacklisted=" + isBlacklisted + ", newRule="
+ + ruleToString(newRule) + ", oldRule=" + ruleToString(oldRule));
+ }
+
+ // dispatch changed rule to existing listeners
mHandler.obtainMessage(MSG_RULES_CHANGED, uid, newRule).sendToTarget();
}
-
- try {
- // adjust stats accounting based on foreground status
- mNetworkStats.setUidForeground(uid, uidForeground);
- } catch (RemoteException e) {
- // ignored; service lives in system_server
- }
}
private class AppIdleStateChangeListener
@@ -2801,11 +2977,23 @@
}
}
- private void setUidNetworkRules(int uid, boolean rejectOnQuotaInterfaces) {
+ private void setMeteredNetworkBlacklist(int uid, boolean enable) {
+ if (LOGV) Slog.v(TAG, "setMeteredNetworkBlacklist " + uid + ": " + enable);
try {
- mNetworkManager.setUidMeteredNetworkBlacklist(uid, rejectOnQuotaInterfaces);
+ mNetworkManager.setUidMeteredNetworkBlacklist(uid, enable);
} catch (IllegalStateException e) {
- Log.wtf(TAG, "problem setting uid rules", e);
+ Log.wtf(TAG, "problem setting blacklist (" + enable + ") rules for " + uid, e);
+ } catch (RemoteException e) {
+ // ignored; service lives in system_server
+ }
+ }
+
+ private void setMeteredNetworkWhitelist(int uid, boolean enable) {
+ if (LOGV) Slog.v(TAG, "setMeteredNetworkWhitelist " + uid + ": " + enable);
+ try {
+ mNetworkManager.setUidMeteredNetworkWhitelist(uid, enable);
+ } catch (IllegalStateException e) {
+ Log.wtf(TAG, "problem setting whitelist (" + enable + ") rules for " + uid, e);
} catch (RemoteException e) {
// ignored; service lives in system_server
}
@@ -2987,7 +3175,7 @@
public void onPackageRemoved(String packageName, int uid) {
if (LOGV) Slog.v(TAG, "onPackageRemoved: " + packageName + " ->" + uid);
synchronized (mRulesLock) {
- removeRestrictBackgroundWhitelistedUidLocked(uid, true);
+ removeRestrictBackgroundWhitelistedUidLocked(uid, true, true);
}
}
}
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerShellCommand.java b/services/core/java/com/android/server/net/NetworkPolicyManagerShellCommand.java
index 9cfb590..d339f69 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerShellCommand.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerShellCommand.java
@@ -24,7 +24,6 @@
import java.io.PrintWriter;
import java.util.ArrayList;
-import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
@@ -35,7 +34,6 @@
import android.net.NetworkTemplate;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiManager;
-import android.os.Binder;
import android.os.RemoteException;
import android.os.ShellCommand;
import android.util.Log;
@@ -88,12 +86,10 @@
pw.println(" Adds a UID to the whitelist for restrict background usage.");
pw.println(" add restrict-background-blacklist UID");
pw.println(" Adds a UID to the blacklist for restrict background usage.");
- pw.println(" get metered-network ID");
- pw.println(" Checks whether the given non-mobile network is metered or not.");
pw.println(" get restrict-background");
pw.println(" Gets the global restrict background usage status.");
- pw.println(" list metered-networks [BOOLEAN]");
- pw.println(" Lists all non-mobile networks and whether they are metered or not.");
+ pw.println(" list wifi-networks [BOOLEAN]");
+ pw.println(" Lists all saved wifi networks and whether they are metered or not.");
pw.println(" If a boolean argument is passed, filters just the metered (or unmetered)");
pw.println(" networks.");
pw.println(" list restrict-background-whitelist");
@@ -105,7 +101,7 @@
pw.println(" remove restrict-background-blacklist UID");
pw.println(" Removes a UID from the blacklist for restrict background usage.");
pw.println(" set metered-network ID BOOLEAN");
- pw.println(" Toggles whether the given non-mobile network is metered.");
+ pw.println(" Toggles whether the given wi-fi network is metered.");
pw.println(" set restrict-background BOOLEAN");
pw.println(" Sets the global restrict background usage status.");
}
@@ -118,8 +114,6 @@
return -1;
}
switch(type) {
- case "metered-network":
- return getMeteredWifiNetwork();
case "restrict-background":
return getRestrictBackground();
}
@@ -152,8 +146,8 @@
return -1;
}
switch(type) {
- case "metered-networks":
- return listMeteredWifiNetworks();
+ case "wifi-networks":
+ return listWifiNetworks();
case "restrict-background-whitelist":
return listRestrictBackgroundWhitelist();
case "restrict-background-blacklist":
@@ -284,7 +278,7 @@
return 0;
}
- private int listMeteredWifiNetworks() throws RemoteException {
+ private int listWifiNetworks() throws RemoteException {
final PrintWriter pw = getOutPrintWriter();
final String arg = getNextArg();
final Boolean filter = arg == null ? null : Boolean.valueOf(arg);
@@ -299,23 +293,6 @@
return 0;
}
- private int getMeteredWifiNetwork() throws RemoteException {
- final PrintWriter pw = getOutPrintWriter();
- final String id = getNextArg();
- if (id == null) {
- pw.println("Error: didn't specify ID");
- return -1;
- }
- final List<NetworkPolicy> policies = getWifiPolicies();
- for (NetworkPolicy policy: policies) {
- if (id.equals(getNetworkId(policy))) {
- pw.println(policy.metered);
- return 0;
- }
- }
- return 0;
- }
-
private int setMeteredWifiNetwork() throws RemoteException {
final PrintWriter pw = getOutPrintWriter();
final String id = getNextArg();
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 0f23fde..660f790 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -120,6 +120,7 @@
import android.widget.Toast;
import com.android.internal.R;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.statusbar.NotificationVisibility;
import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.Preconditions;
@@ -226,7 +227,7 @@
private VrManagerInternal mVrManagerInternal;
final IBinder mForegroundToken = new Binder();
- private WorkerHandler mHandler;
+ private Handler mHandler;
private final HandlerThread mRankingThread = new HandlerThread("ranker",
Process.THREAD_PRIORITY_BACKGROUND);
@@ -572,33 +573,9 @@
public void clearEffects() {
synchronized (mNotificationList) {
if (DBG) Slog.d(TAG, "clearEffects");
-
- // sound
- mSoundNotificationKey = null;
-
- long identity = Binder.clearCallingIdentity();
- try {
- final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
- if (player != null) {
- player.stopAsync();
- }
- } catch (RemoteException e) {
- } finally {
- Binder.restoreCallingIdentity(identity);
- }
-
- // vibrate
- mVibrateNotificationKey = null;
- identity = Binder.clearCallingIdentity();
- try {
- mVibrator.cancel();
- } finally {
- Binder.restoreCallingIdentity(identity);
- }
-
- // light
- mLights.clear();
- updateLightsLocked();
+ clearSoundLocked();
+ clearVibrateLocked();
+ clearLightsLocked();
}
}
@@ -658,6 +635,36 @@
}
};
+ private void clearSoundLocked() {
+ mSoundNotificationKey = null;
+ long identity = Binder.clearCallingIdentity();
+ try {
+ final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
+ if (player != null) {
+ player.stopAsync();
+ }
+ } catch (RemoteException e) {
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
+ private void clearVibrateLocked() {
+ mVibrateNotificationKey = null;
+ long identity = Binder.clearCallingIdentity();
+ try {
+ mVibrator.cancel();
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
+ private void clearLightsLocked() {
+ // light
+ mLights.clear();
+ updateLightsLocked();
+ }
+
private final BroadcastReceiver mPackageIntentReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
@@ -764,10 +771,9 @@
cancelAllNotificationsInt(MY_UID, MY_PID, null, 0, 0, true, userHandle,
REASON_USER_STOPPED, null);
}
- } else if (action.equals(Intent.ACTION_MANAGED_PROFILE_AVAILABILITY_CHANGED)) {
- boolean inQuietMode = intent.getBooleanExtra(Intent.EXTRA_QUIET_MODE, false);
+ } else if (action.equals(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE)) {
int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
- if (inQuietMode && userHandle >= 0) {
+ if (userHandle >= 0) {
cancelAllNotificationsInt(MY_UID, MY_PID, null, 0, 0, true, userHandle,
REASON_PROFILE_TURNED_OFF, null);
}
@@ -863,6 +869,26 @@
super(context);
}
+ @VisibleForTesting
+ void setAudioManager(AudioManager audioMananger) {
+ mAudioManager = audioMananger;
+ }
+
+ @VisibleForTesting
+ void setVibrator(Vibrator vibrator) {
+ mVibrator = vibrator;
+ }
+
+ @VisibleForTesting
+ void setSystemReady(boolean systemReady) {
+ mSystemReady = systemReady;
+ }
+
+ @VisibleForTesting
+ void setHandler(Handler handler) {
+ mHandler = handler;
+ }
+
@Override
public void onStart() {
Resources resources = getContext().getResources();
@@ -981,7 +1007,7 @@
filter.addAction(Intent.ACTION_USER_ADDED);
filter.addAction(Intent.ACTION_USER_REMOVED);
filter.addAction(Intent.ACTION_USER_UNLOCKED);
- filter.addAction(Intent.ACTION_MANAGED_PROFILE_AVAILABILITY_CHANGED);
+ filter.addAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE);
getContext().registerReceiver(mIntentReceiver, filter);
IntentFilter pkgFilter = new IntentFilter();
@@ -1852,10 +1878,16 @@
}
private boolean checkPolicyAccess(String pkg) {
- if (PackageManager.PERMISSION_GRANTED == ActivityManager.checkComponentPermission(
- android.Manifest.permission.MANAGE_NOTIFICATIONS, Binder.getCallingUid(),
- -1, true)) {
- return true;
+ try {
+ int uid = getContext().getPackageManager().getPackageUidAsUser(
+ pkg, UserHandle.getCallingUserId());
+ if (PackageManager.PERMISSION_GRANTED == ActivityManager.checkComponentPermission(
+ android.Manifest.permission.MANAGE_NOTIFICATIONS, uid,
+ -1, true)) {
+ return true;
+ }
+ } catch (NameNotFoundException e) {
+ return false;
}
return checkPackagePolicyAccess(pkg) || mListeners.isComponentEnabledForPackage(pkg);
}
@@ -2486,12 +2518,14 @@
return false;
}
- private void buzzBeepBlinkLocked(NotificationRecord record) {
+ @VisibleForTesting
+ void buzzBeepBlinkLocked(NotificationRecord record) {
boolean buzz = false;
boolean beep = false;
boolean blink = false;
final Notification notification = record.sbn.getNotification();
+ final String key = record.getKey();
// Should this notification make noise, vibe, or use the LED?
final boolean aboveThreshold = record.getImportance() >= IMPORTANCE_DEFAULT;
@@ -2515,9 +2549,15 @@
if (disableEffects != null) {
ZenLog.traceDisableEffects(record, disableEffects);
}
+
+ // Remember if this notification already owns the notification channels.
+ boolean wasBeep = key != null && key.equals(mSoundNotificationKey);
+ boolean wasBuzz = key != null && key.equals(mVibrateNotificationKey);
+
+ // These are set inside the conditional if the notification is allowed to make noise.
+ boolean hasValidVibrate = false;
+ boolean hasValidSound = false;
if (disableEffects == null
- && (!(record.isUpdate
- && (notification.flags & Notification.FLAG_ONLY_ALERT_ONCE) != 0 ))
&& (record.getUserId() == UserHandle.USER_ALL ||
record.getUserId() == currentUser ||
mUserProfiles.isCurrentProfile(record.getUserId()))
@@ -2526,10 +2566,6 @@
&& mAudioManager != null) {
if (DBG) Slog.v(TAG, "Interrupting!");
- sendAccessibilityEvent(notification, record.sbn.getPackageName());
-
- // sound
-
// should we use the default notification sound? (indicated either by
// DEFAULT_SOUND or because notification.sound is pointing at
// Settings.System.NOTIFICATION_SOUND)
@@ -2539,8 +2575,6 @@
.equals(notification.sound);
Uri soundUri = null;
- boolean hasValidSound = false;
-
if (useDefaultSound) {
soundUri = Settings.System.DEFAULT_NOTIFICATION_URI;
@@ -2553,88 +2587,105 @@
hasValidSound = (soundUri != null);
}
- if (hasValidSound) {
- boolean looping =
- (notification.flags & Notification.FLAG_INSISTENT) != 0;
- AudioAttributes audioAttributes = audioAttributesForNotification(notification);
- mSoundNotificationKey = record.getKey();
- // do not play notifications if stream volume is 0 (typically because
- // ringer mode is silent) or if there is a user of exclusive audio focus
- if ((mAudioManager.getStreamVolume(
- AudioAttributes.toLegacyStreamType(audioAttributes)) != 0)
- && !mAudioManager.isAudioFocusExclusive()) {
- final long identity = Binder.clearCallingIdentity();
- try {
- final IRingtonePlayer player =
- mAudioManager.getRingtonePlayer();
- if (player != null) {
- if (DBG) Slog.v(TAG, "Playing sound " + soundUri
- + " with attributes " + audioAttributes);
- player.playAsync(soundUri, record.sbn.getUser(), looping,
- audioAttributes);
- beep = true;
- }
- } catch (RemoteException e) {
- } finally {
- Binder.restoreCallingIdentity(identity);
- }
- }
- }
-
- // vibrate
// Does the notification want to specify its own vibration?
final boolean hasCustomVibrate = notification.vibrate != null;
// new in 4.2: if there was supposed to be a sound and we're in vibrate
// mode, and no other vibration is specified, we fall back to vibration
final boolean convertSoundToVibration =
- !hasCustomVibrate
- && hasValidSound
- && (mAudioManager.getRingerModeInternal()
- == AudioManager.RINGER_MODE_VIBRATE);
+ !hasCustomVibrate
+ && hasValidSound
+ && (mAudioManager.getRingerModeInternal() == AudioManager.RINGER_MODE_VIBRATE);
// The DEFAULT_VIBRATE flag trumps any custom vibration AND the fallback.
final boolean useDefaultVibrate =
(notification.defaults & Notification.DEFAULT_VIBRATE) != 0;
- if ((useDefaultVibrate || convertSoundToVibration || hasCustomVibrate)
- && !(mAudioManager.getRingerModeInternal()
- == AudioManager.RINGER_MODE_SILENT)) {
- mVibrateNotificationKey = record.getKey();
+ hasValidVibrate = useDefaultVibrate || convertSoundToVibration ||
+ hasCustomVibrate;
- if (useDefaultVibrate || convertSoundToVibration) {
- // Escalate privileges so we can use the vibrator even if the
- // notifying app does not have the VIBRATE permission.
- long identity = Binder.clearCallingIdentity();
- try {
- mVibrator.vibrate(record.sbn.getUid(), record.sbn.getOpPkg(),
- useDefaultVibrate ? mDefaultVibrationPattern
- : mFallbackVibrationPattern,
- ((notification.flags & Notification.FLAG_INSISTENT) != 0)
- ? 0: -1, audioAttributesForNotification(notification));
- buzz = true;
- } finally {
- Binder.restoreCallingIdentity(identity);
+ // We can alert, and we're allowed to alert, but if the developer asked us to only do
+ // it once, and we already have, then don't.
+ if (!(record.isUpdate
+ && (notification.flags & Notification.FLAG_ONLY_ALERT_ONCE) != 0)) {
+
+ sendAccessibilityEvent(notification, record.sbn.getPackageName());
+
+ if (hasValidSound) {
+ boolean looping =
+ (notification.flags & Notification.FLAG_INSISTENT) != 0;
+ AudioAttributes audioAttributes = audioAttributesForNotification(notification);
+ mSoundNotificationKey = key;
+ // do not play notifications if stream volume is 0 (typically because
+ // ringer mode is silent) or if there is a user of exclusive audio focus
+ if ((mAudioManager.getStreamVolume(
+ AudioAttributes.toLegacyStreamType(audioAttributes)) != 0)
+ && !mAudioManager.isAudioFocusExclusive()) {
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ final IRingtonePlayer player =
+ mAudioManager.getRingtonePlayer();
+ if (player != null) {
+ if (DBG) Slog.v(TAG, "Playing sound " + soundUri
+ + " with attributes " + audioAttributes);
+ player.playAsync(soundUri, record.sbn.getUser(), looping,
+ audioAttributes);
+ beep = true;
+ }
+ } catch (RemoteException e) {
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
}
- } else if (notification.vibrate.length > 1) {
- // If you want your own vibration pattern, you need the VIBRATE
- // permission
- mVibrator.vibrate(record.sbn.getUid(), record.sbn.getOpPkg(),
- notification.vibrate,
- ((notification.flags & Notification.FLAG_INSISTENT) != 0)
- ? 0: -1, audioAttributesForNotification(notification));
- buzz = true;
+ }
+
+ if (hasValidVibrate && !(mAudioManager.getRingerModeInternal()
+ == AudioManager.RINGER_MODE_SILENT)) {
+ mVibrateNotificationKey = key;
+
+ if (useDefaultVibrate || convertSoundToVibration) {
+ // Escalate privileges so we can use the vibrator even if the
+ // notifying app does not have the VIBRATE permission.
+ long identity = Binder.clearCallingIdentity();
+ try {
+ mVibrator.vibrate(record.sbn.getUid(), record.sbn.getOpPkg(),
+ useDefaultVibrate ? mDefaultVibrationPattern
+ : mFallbackVibrationPattern,
+ ((notification.flags & Notification.FLAG_INSISTENT) != 0)
+ ? 0: -1, audioAttributesForNotification(notification));
+ buzz = true;
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ } else if (notification.vibrate.length > 1) {
+ // If you want your own vibration pattern, you need the VIBRATE
+ // permission
+ mVibrator.vibrate(record.sbn.getUid(), record.sbn.getOpPkg(),
+ notification.vibrate,
+ ((notification.flags & Notification.FLAG_INSISTENT) != 0)
+ ? 0: -1, audioAttributesForNotification(notification));
+ buzz = true;
+ }
}
}
+
+ }
+ // If a notification is updated to remove the actively playing sound or vibrate,
+ // cancel that feedback now
+ if (wasBeep && !hasValidSound) {
+ clearSoundLocked();
+ }
+ if (wasBuzz && !hasValidVibrate) {
+ clearVibrateLocked();
}
// light
// release the light
- boolean wasShowLights = mLights.remove(record.getKey());
+ boolean wasShowLights = mLights.remove(key);
if ((notification.flags & Notification.FLAG_SHOW_LIGHTS) != 0 && aboveThreshold
&& ((record.getSuppressedVisualEffects()
& NotificationListenerService.SUPPRESSED_EFFECT_SCREEN_OFF) == 0)) {
- mLights.add(record.getKey());
+ mLights.add(key);
updateLightsLocked();
if (mUseAttentionLight) {
mAttentionLight.pulse();
@@ -2648,7 +2699,7 @@
& NotificationListenerService.SUPPRESSED_EFFECT_SCREEN_OFF) != 0)) {
if (DBG) Slog.v(TAG, "Suppressed SystemUI from triggering screen on");
} else {
- EventLogTags.writeNotificationAlert(record.getKey(),
+ EventLogTags.writeNotificationAlert(key,
buzz ? 1 : 0, beep ? 1 : 0, blink ? 1 : 0);
mHandler.post(mBuzzBeepBlinked);
}
@@ -3435,6 +3486,9 @@
return AppGlobals.getPackageManager().isPackageSuspendedForUser(pkg, userId);
} catch (RemoteException re) {
throw new SecurityException("Could not talk to package manager service");
+ } catch (IllegalArgumentException ex) {
+ // Package not found.
+ return false;
}
}
diff --git a/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java
index 13a96ae..098b39e 100644
--- a/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java
+++ b/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java
@@ -247,10 +247,8 @@
}
// SetupWizard
- Intent setupIntent = new Intent(Intent.ACTION_MAIN);
- setupIntent.addCategory(Intent.CATEGORY_SETUP_WIZARD);
- PackageParser.Package setupPackage = getDefaultSystemHandlerActivityPackageLPr(
- setupIntent, userId);
+ PackageParser.Package setupPackage = getSystemPackageLPr(
+ mService.mSetupWizardPackage);
if (setupPackage != null
&& doesPackageSupportRuntimePermissions(setupPackage)) {
grantRuntimePermissionsLPw(setupPackage, PHONE_PERMISSIONS, userId);
@@ -597,6 +595,16 @@
grantRuntimePermissionsLPw(emergencyInfoPckg, PHONE_PERMISSIONS, true, userId);
}
+ // NFC Tag viewer
+ Intent nfcTagIntent = new Intent(Intent.ACTION_VIEW);
+ nfcTagIntent.setType("vnd.android.cursor.item/ndef_msg");
+ PackageParser.Package nfcTagPkg = getDefaultSystemHandlerActivityPackageLPr(
+ nfcTagIntent, userId);
+ if (nfcTagPkg != null
+ && doesPackageSupportRuntimePermissions(nfcTagPkg)) {
+ grantRuntimePermissionsLPw(nfcTagPkg, CONTACTS_PERMISSIONS, false, userId);
+ grantRuntimePermissionsLPw(nfcTagPkg, PHONE_PERMISSIONS, false, userId);
+ }
mService.mSettings.onDefaultRuntimePermissionsGrantedLPr(userId);
}
}
diff --git a/services/core/java/com/android/server/pm/LauncherAppsService.java b/services/core/java/com/android/server/pm/LauncherAppsService.java
index c303ceb..4c18e15 100644
--- a/services/core/java/com/android/server/pm/LauncherAppsService.java
+++ b/services/core/java/com/android/server/pm/LauncherAppsService.java
@@ -60,6 +60,7 @@
import com.android.server.LocalServices;
import com.android.server.SystemService;
+import java.util.ArrayList;
import java.util.List;
/**
@@ -77,7 +78,6 @@
@Override
public void onStart() {
- Binder.LOG_RUNTIME_EXCEPTION = true;
publishBinderService(Context.LAUNCHER_APPS_SERVICE, mLauncherAppsImpl);
}
@@ -121,6 +121,21 @@
return getCallingUid();
}
+ final int injectCallingUserId() {
+ return UserHandle.getUserId(injectBinderCallingUid());
+ }
+
+ @VisibleForTesting
+ long injectClearCallingIdentity() {
+ return Binder.clearCallingIdentity();
+ }
+
+ // Injection point.
+ @VisibleForTesting
+ void injectRestoreCallingIdentity(long token) {
+ Binder.restoreCallingIdentity(token);
+ }
+
private int getCallingUserId() {
return UserHandle.getUserId(injectBinderCallingUid());
}
@@ -197,14 +212,13 @@
/**
* Checks if the caller is in the same group as the userToCheck.
*/
- @VisibleForTesting // We override it in unit tests
- void ensureInUserProfiles(UserHandle userToCheck, String message) {
- final int callingUserId = UserHandle.getCallingUserId();
+ private void ensureInUserProfiles(UserHandle userToCheck, String message) {
+ final int callingUserId = injectCallingUserId();
final int targetUserId = userToCheck.getIdentifier();
if (targetUserId == callingUserId) return;
- long ident = Binder.clearCallingIdentity();
+ long ident = injectClearCallingIdentity();
try {
UserInfo callingUserInfo = mUm.getUserInfo(callingUserId);
UserInfo targetUserInfo = mUm.getUserInfo(targetUserId);
@@ -214,7 +228,7 @@
throw new SecurityException(message);
}
} finally {
- Binder.restoreCallingIdentity(ident);
+ injectRestoreCallingIdentity(ident);
}
}
@@ -239,12 +253,12 @@
* Checks if the user is enabled.
*/
private boolean isUserEnabled(UserHandle user) {
- long ident = Binder.clearCallingIdentity();
+ long ident = injectClearCallingIdentity();
try {
UserInfo targetUserInfo = mUm.getUserInfo(user.getIdentifier());
return targetUserInfo != null && targetUserInfo.isEnabled();
} finally {
- Binder.restoreCallingIdentity(ident);
+ injectRestoreCallingIdentity(ident);
}
}
@@ -335,75 +349,102 @@
verifyCallingPackage(callingPackage);
ensureInUserProfiles(user, "Cannot start activity for unrelated profile " + user);
- if (!mShortcutServiceInternal.hasShortcutHostPermission(callingPackage,
- user.getIdentifier())) {
+ if (!mShortcutServiceInternal.hasShortcutHostPermission(getCallingUserId(),
+ callingPackage)) {
throw new SecurityException("Caller can't access shortcut information");
}
}
@Override
public ParceledListSlice getShortcuts(String callingPackage, long changedSince,
- String packageName, ComponentName componentName, int flags, UserHandle user)
- throws RemoteException {
+ String packageName, ComponentName componentName, int flags, UserHandle user) {
ensureShortcutPermission(callingPackage, user);
+ if (!isUserEnabled(user)) {
+ return new ParceledListSlice<>(new ArrayList(0));
+ }
return new ParceledListSlice<>(
- mShortcutServiceInternal.getShortcuts(callingPackage, changedSince, packageName,
- componentName, flags, user.getIdentifier()));
+ mShortcutServiceInternal.getShortcuts(getCallingUserId(),
+ callingPackage, changedSince, packageName,
+ componentName, flags, user.getIdentifier()));
}
@Override
public ParceledListSlice getShortcutInfo(String callingPackage, String packageName,
- List<String> ids, UserHandle user) throws RemoteException {
+ List<String> ids, UserHandle user) {
ensureShortcutPermission(callingPackage, user);
+ if (!isUserEnabled(user)) {
+ return new ParceledListSlice<>(new ArrayList(0));
+ }
return new ParceledListSlice<>(
- mShortcutServiceInternal.getShortcutInfo(callingPackage, packageName,
- ids, user.getIdentifier()));
+ mShortcutServiceInternal.getShortcutInfo(getCallingUserId(),
+ callingPackage, packageName, ids, user.getIdentifier()));
}
@Override
public void pinShortcuts(String callingPackage, String packageName, List<String> ids,
- UserHandle user) throws RemoteException {
+ UserHandle user) {
ensureShortcutPermission(callingPackage, user);
+ if (!isUserEnabled(user)) {
+ throw new IllegalStateException("Cannot pin shortcuts for disabled profile "
+ + user);
+ }
- mShortcutServiceInternal.pinShortcuts(callingPackage, packageName,
- ids, user.getIdentifier());
+ mShortcutServiceInternal.pinShortcuts(getCallingUserId(),
+ callingPackage, packageName, ids, user.getIdentifier());
}
@Override
public int getShortcutIconResId(String callingPackage, ShortcutInfo shortcut,
UserHandle user) {
ensureShortcutPermission(callingPackage, user);
+ if (!isUserEnabled(user)) {
+ return 0;
+ }
- return mShortcutServiceInternal.getShortcutIconResId(callingPackage, shortcut,
- user.getIdentifier());
+ return mShortcutServiceInternal.getShortcutIconResId(getCallingUserId(),
+ callingPackage, shortcut, user.getIdentifier());
}
@Override
public ParcelFileDescriptor getShortcutIconFd(String callingPackage, ShortcutInfo shortcut,
UserHandle user) {
ensureShortcutPermission(callingPackage, user);
+ if (!isUserEnabled(user)) {
+ return null;
+ }
- return mShortcutServiceInternal.getShortcutIconFd(callingPackage, shortcut,
- user.getIdentifier());
+ return mShortcutServiceInternal.getShortcutIconFd(getCallingUserId(),
+ callingPackage, shortcut, user.getIdentifier());
}
@Override
- public boolean hasShortcutHostPermission(String callingPackage) throws RemoteException {
+ public boolean hasShortcutHostPermission(String callingPackage) {
verifyCallingPackage(callingPackage);
- return mShortcutServiceInternal.hasShortcutHostPermission(callingPackage,
- getCallingUserId());
+ return mShortcutServiceInternal.hasShortcutHostPermission(getCallingUserId(),
+ callingPackage);
}
@Override
public boolean startShortcut(String callingPackage, String packageName, String shortcutId,
- Rect sourceBounds, Bundle startActivityOptions, UserHandle user)
- throws RemoteException {
- ensureShortcutPermission(callingPackage, user);
+ Rect sourceBounds, Bundle startActivityOptions, UserHandle user) {
+ verifyCallingPackage(callingPackage);
+ ensureInUserProfiles(user, "Cannot start activity for unrelated profile " + user);
- final Intent intent = mShortcutServiceInternal.createShortcutIntent(callingPackage,
- packageName, shortcutId, user.getIdentifier());
+ if (!isUserEnabled(user)) {
+ throw new IllegalStateException("Cannot start a shortcut for disabled profile "
+ + user);
+ }
+
+ // Even without the permission, pinned shortcuts are always launchable.
+ if (!mShortcutServiceInternal.isPinnedByCaller(getCallingUserId(),
+ callingPackage, packageName, shortcutId, user.getIdentifier())) {
+ ensureShortcutPermission(callingPackage, user);
+ }
+
+ final Intent intent = mShortcutServiceInternal.createShortcutIntent(getCallingUserId(),
+ callingPackage, packageName, shortcutId, user.getIdentifier());
if (intent == null) {
return false;
}
@@ -524,13 +565,13 @@
/** Checks if user is a profile of or same as listeningUser.
* and the user is enabled. */
- boolean isEnabledProfileOf(UserHandle user, UserHandle listeningUser,
+ private boolean isEnabledProfileOf(UserHandle user, UserHandle listeningUser,
String debugMsg) {
if (user.getIdentifier() == listeningUser.getIdentifier()) {
if (DEBUG) Log.d(TAG, "Delivering msg to same user " + debugMsg);
return true;
}
- long ident = Binder.clearCallingIdentity();
+ long ident = injectClearCallingIdentity();
try {
UserInfo userInfo = mUm.getUserInfo(user.getIdentifier());
UserInfo listeningUserInfo = mUm.getUserInfo(listeningUser.getIdentifier());
@@ -551,7 +592,7 @@
return true;
}
} finally {
- Binder.restoreCallingIdentity(ident);
+ injectRestoreCallingIdentity(ident);
}
}
@@ -713,9 +754,11 @@
BroadcastCookie cookie = (BroadcastCookie) mListeners.getBroadcastCookie(i);
if (!isEnabledProfileOf(user, cookie.user, "onShortcutChanged")) continue;
+ final int launcherUserId = cookie.user.getIdentifier();
+
// Make sure the caller has the permission.
- if (!mShortcutServiceInternal.hasShortcutHostPermission(cookie.packageName,
- cookie.user.getIdentifier())) {
+ if (!mShortcutServiceInternal.hasShortcutHostPermission(
+ launcherUserId, cookie.packageName)) {
continue;
}
// Each launcher has a different set of pinned shortcuts, so we need to do a
@@ -723,8 +766,9 @@
// (As of now, only one launcher has the permission at a time, so it's bit
// moot, but we may change the permission model eventually.)
final List<ShortcutInfo> list =
- mShortcutServiceInternal.getShortcuts(cookie.packageName,
- /* changedSince= */ 0, packageName, /* component= */ null,
+ mShortcutServiceInternal.getShortcuts(launcherUserId,
+ cookie.packageName,
+ /* changedSince= */ 0, packageName, /* component= */ null,
ShortcutQuery.FLAG_GET_KEY_FIELDS_ONLY
| ShortcutQuery.FLAG_GET_PINNED
| ShortcutQuery.FLAG_GET_DYNAMIC
diff --git a/services/core/java/com/android/server/pm/PackageDexOptimizer.java b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
index 5ceb65f..d13f472 100644
--- a/services/core/java/com/android/server/pm/PackageDexOptimizer.java
+++ b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
@@ -42,7 +42,7 @@
import static com.android.server.pm.Installer.DEXOPT_SAFEMODE;
import static com.android.server.pm.InstructionSets.getAppDexInstructionSets;
import static com.android.server.pm.InstructionSets.getDexCodeInstructionSets;
-import static com.android.server.pm.PackageManagerServiceCompilerMapping.getFullCompilerFilter;
+import static com.android.server.pm.PackageManagerServiceCompilerMapping.getNonProfileGuidedCompilerFilter;
/**
* Helper class for running dexopt command on packages.
@@ -138,16 +138,16 @@
boolean isProfileGuidedFilter = DexFile.isProfileGuidedCompilerFilter(targetCompilerFilter);
// If any part of the app is used by other apps, we cannot use profile-guided
// compilation.
- // TODO: This needs to be refactored to be also checked when the target mode is
- // profile-guided.
- if (isProfileGuidedFilter) {
+ // Skip the check for forward locked packages since they don't share their code.
+ if (isProfileGuidedFilter && !pkg.isForwardLocked()) {
for (String path : paths) {
if (isUsedByOtherApps(path)) {
checkProfiles = false;
- // TODO: Should we only upgrade to the non-profile-guided version? That is,
- // given verify-profile, should we move to interpret-only?
- targetCompilerFilter = getFullCompilerFilter();
+ targetCompilerFilter = getNonProfileGuidedCompilerFilter(targetCompilerFilter);
+ if (DexFile.isProfileGuidedCompilerFilter(targetCompilerFilter)) {
+ throw new IllegalStateException(targetCompilerFilter);
+ }
isProfileGuidedFilter = false;
break;
@@ -182,6 +182,10 @@
return DEX_OPT_FAILED;
}
dexoptNeeded = adjustDexoptNeeded(dexoptNeeded);
+ if (PackageManagerService.DEBUG_DEXOPT) {
+ Log.i(TAG, "DexoptNeeded for " + path + "@" + targetCompilerFilter + " is " +
+ dexoptNeeded);
+ }
final String dexoptType;
String oatDir = null;
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index a937738..4ce730f 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -64,6 +64,7 @@
import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_AWARE;
import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_UNAWARE;
import static android.content.pm.PackageManager.MATCH_DISABLED_COMPONENTS;
+import static android.content.pm.PackageManager.MATCH_FACTORY_ONLY;
import static android.content.pm.PackageManager.MATCH_SYSTEM_ONLY;
import static android.content.pm.PackageManager.MATCH_UNINSTALLED_PACKAGES;
import static android.content.pm.PackageManager.MOVE_FAILED_DEVICE_ADMIN;
@@ -75,6 +76,7 @@
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.content.pm.PackageParser.PARSE_IS_PRIVILEGED;
import static android.content.pm.PackageParser.isApkFile;
+import static android.os.Process.FIRST_APPLICATION_UID;
import static android.os.Process.PACKAGE_INFO_GID;
import static android.os.Process.SYSTEM_UID;
import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
@@ -106,6 +108,7 @@
import android.app.IActivityManager;
import android.app.admin.DevicePolicyManagerInternal;
import android.app.admin.IDevicePolicyManager;
+import android.app.admin.SecurityLog;
import android.app.backup.IBackupManager;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
@@ -113,6 +116,7 @@
import android.content.IIntentReceiver;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.IntentFilter.AuthorityEntry;
import android.content.IntentSender;
import android.content.IntentSender.SendIntentException;
import android.content.ServiceConnection;
@@ -145,6 +149,7 @@
import android.content.pm.PackageManagerInternal;
import android.content.pm.PackageParser;
import android.content.pm.PackageParser.ActivityIntentInfo;
+import android.content.pm.PackageParser.IntentInfo;
import android.content.pm.PackageParser.PackageLite;
import android.content.pm.PackageParser.PackageParserException;
import android.content.pm.PackageStats;
@@ -318,6 +323,7 @@
private static final boolean DEBUG_INTENT_MATCHING = false;
private static final boolean DEBUG_PACKAGE_SCANNING = false;
private static final boolean DEBUG_VERIFY = false;
+ private static final boolean DEBUG_FILTERS = false;
// Debug output for dexopting. This is shared between PackageManagerService, OtaDexoptService
// and PackageDexOptimizer. All these classes have their own flag to allow switching a single
@@ -443,6 +449,18 @@
sBrowserIntent.setData(Uri.parse("http:"));
}
+ /**
+ * The set of all protected actions [i.e. those actions for which a high priority
+ * intent filter is disallowed].
+ */
+ private static final Set<String> PROTECTED_ACTIONS = new ArraySet<>();
+ static {
+ PROTECTED_ACTIONS.add(Intent.ACTION_SEND);
+ PROTECTED_ACTIONS.add(Intent.ACTION_SENDTO);
+ PROTECTED_ACTIONS.add(Intent.ACTION_SEND_MULTIPLE);
+ PROTECTED_ACTIONS.add(Intent.ACTION_VIEW);
+ }
+
// Compilation reasons.
public static final int REASON_FIRST_BOOT = 0;
public static final int REASON_BOOT = 1;
@@ -459,6 +477,8 @@
final PackageHandler mHandler;
+ private final ProcessLoggingHandler mProcessLoggingHandler;
+
/**
* Messages for {@link #mHandler} that need to wait for system ready before
* being dispatched.
@@ -527,6 +547,20 @@
* are package location.
*/
final private ArrayMap<String, File> mExpectingBetter = new ArrayMap<>();
+ /**
+ * Tracks high priority intent filters for protected actions. During boot, certain
+ * filter actions are protected and should never be allowed to have a high priority
+ * intent filter for them. However, there is one, and only one exception -- the
+ * setup wizard. It must be able to define a high priority intent filter for these
+ * actions to ensure there are no escapes from the wizard. We need to delay processing
+ * of these during boot as we need to look at all of the system packages in order
+ * to know which component is the setup wizard.
+ */
+ private final List<PackageParser.ActivityIntentInfo> mProtectedFilters = new ArrayList<>();
+ /**
+ * Whether or not processing protected filters should be deferred.
+ */
+ private boolean mDeferProtectedFilters = true;
/**
* Tracks existing system packages prior to receiving an OTA. Keys are package name.
@@ -1031,6 +1065,7 @@
final @Nullable String mRequiredVerifierPackage;
final @Nullable String mRequiredInstallerPackage;
+ final @Nullable String mSetupWizardPackage;
private final PackageUsage mPackageUsage = new PackageUsage();
@@ -1712,6 +1747,8 @@
// Send installed broadcasts if the install/update is not ephemeral
if (!isEphemeral(res.pkg)) {
+ mProcessLoggingHandler.invalidateProcessLoggingBaseApkHash(res.pkg.baseCodePath);
+
// Send added for users that see the package for the first time
sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, packageName,
extras, 0 /*flags*/, null /*targetPackage*/,
@@ -2096,6 +2133,7 @@
Process.THREAD_PRIORITY_BACKGROUND, true /*allowIo*/);
mHandlerThread.start();
mHandler = new PackageHandler(mHandlerThread.getLooper());
+ mProcessLoggingHandler = new ProcessLoggingHandler();
Watchdog.getInstance().addThread(mHandler, WATCHDOG_TIMEOUT);
File dataDir = Environment.getDataDirectory();
@@ -2225,9 +2263,10 @@
}
}
- // When upgrading form pre-N, we need to handle package extraction like first boot,
+ // When upgrading from pre-N, we need to handle package extraction like first boot,
// as there is no profiling data available.
- mIsPreNUpgrade = ver.sdkVersion <= Build.VERSION_CODES.M;
+ mIsPreNUpgrade = !mSettings.isNWorkDone();
+ mSettings.setNWorkDone();
// Collect vendor overlay packages.
// (Do this before scanning any apps.)
@@ -2420,6 +2459,36 @@
}
mExpectingBetter.clear();
+ // Resolve protected action filters. Only the setup wizard is allowed to
+ // have a high priority filter for these actions.
+ mSetupWizardPackage = getSetupWizardPackageName();
+ if (mProtectedFilters.size() > 0) {
+ if (DEBUG_FILTERS && mSetupWizardPackage == null) {
+ Slog.i(TAG, "No setup wizard;"
+ + " All protected intents capped to priority 0");
+ }
+ for (ActivityIntentInfo filter : mProtectedFilters) {
+ if (filter.activity.info.packageName.equals(mSetupWizardPackage)) {
+ if (DEBUG_FILTERS) {
+ Slog.i(TAG, "Found setup wizard;"
+ + " allow priority " + filter.getPriority() + ";"
+ + " package: " + filter.activity.info.packageName
+ + " activity: " + filter.activity.className
+ + " priority: " + filter.getPriority());
+ }
+ // skip setup wizard; allow it to keep the high priority filter
+ continue;
+ }
+ Slog.w(TAG, "Protected action; cap priority to 0;"
+ + " package: " + filter.activity.info.packageName
+ + " activity: " + filter.activity.className
+ + " origPrio: " + filter.getPriority());
+ filter.setPriority(0);
+ }
+ }
+ mDeferProtectedFilters = false;
+ mProtectedFilters.clear();
+
// Now that we know all of the shared libraries, update all clients to have
// the correct library paths.
updateAllSharedLibrariesLPw();
@@ -2879,12 +2948,15 @@
return cur;
}
- PackageInfo generatePackageInfo(PackageParser.Package p, int flags, int userId) {
+ private PackageInfo generatePackageInfo(PackageSetting ps, int flags, int userId) {
if (!sUserManager.exists(userId)) return null;
- final PackageSetting ps = (PackageSetting) p.mExtras;
if (ps == null) {
return null;
}
+ final PackageParser.Package p = ps.pkg;
+ if (p == null) {
+ return null;
+ }
final PermissionsState permissionsState = ps.getPermissionsState();
@@ -2906,6 +2978,11 @@
throw new SecurityException("Package " + packageName + " was not found!");
}
+ if (!ps.getInstalled(userId)) {
+ throw new SecurityException(
+ "Package " + packageName + " was not installed for user " + userId + "!");
+ }
+
if (mSafeMode && !ps.isSystem()) {
throw new SecurityException("Package " + packageName + " not a system app!");
}
@@ -2949,14 +3026,28 @@
false /* requireFullPermission */, false /* checkShell */, "get package info");
// reader
synchronized (mPackages) {
- PackageParser.Package p = mPackages.get(packageName);
+ final boolean matchFactoryOnly = (flags & MATCH_FACTORY_ONLY) != 0;
+ PackageParser.Package p = null;
+ if (matchFactoryOnly) {
+ final PackageSetting ps = mSettings.getDisabledSystemPkgLPr(packageName);
+ if (ps != null) {
+ return generatePackageInfo(ps, flags, userId);
+ }
+ }
+ if (p == null) {
+ p = mPackages.get(packageName);
+ if (matchFactoryOnly && !isSystemApp(p)) {
+ return null;
+ }
+ }
if (DEBUG_PACKAGE_INFO)
Log.v(TAG, "getPackageInfo " + packageName + ": " + p);
if (p != null) {
- return generatePackageInfo(p, flags, userId);
+ return generatePackageInfo((PackageSetting)p.mExtras, flags, userId);
}
- if ((flags & MATCH_UNINSTALLED_PACKAGES) != 0) {
- return generatePackageInfoFromSettingsLPw(packageName, flags, userId);
+ if (!matchFactoryOnly && (flags & MATCH_UNINSTALLED_PACKAGES) != 0) {
+ final PackageSetting ps = mSettings.mPackages.get(packageName);
+ return generatePackageInfo(ps, flags, userId);
}
}
return null;
@@ -3117,8 +3208,7 @@
PackageSetting ps = mSettings.mPackages.get(packageName);
if (ps != null) {
if (ps.pkg == null) {
- PackageInfo pInfo = generatePackageInfoFromSettingsLPw(packageName,
- flags, userId);
+ final PackageInfo pInfo = generatePackageInfo(ps, flags, userId);
if (pInfo != null) {
return pInfo.applicationInfo;
}
@@ -3130,31 +3220,6 @@
return null;
}
- private PackageInfo generatePackageInfoFromSettingsLPw(String packageName, int flags,
- int userId) {
- if (!sUserManager.exists(userId)) return null;
- PackageSetting ps = mSettings.mPackages.get(packageName);
- if (ps != null) {
- PackageParser.Package pkg = ps.pkg;
- if (pkg == null) {
- if ((flags & MATCH_UNINSTALLED_PACKAGES) == 0) {
- return null;
- }
- // Only data remains, so we aren't worried about code paths
- pkg = new PackageParser.Package(packageName);
- pkg.applicationInfo.packageName = packageName;
- pkg.applicationInfo.flags = ps.pkgFlags | ApplicationInfo.FLAG_IS_DATA_ONLY;
- pkg.applicationInfo.privateFlags = ps.pkgPrivateFlags;
- pkg.applicationInfo.uid = ps.appId;
- pkg.applicationInfo.initForUser(userId);
- pkg.applicationInfo.primaryCpuAbi = ps.primaryCpuAbiString;
- pkg.applicationInfo.secondaryCpuAbi = ps.secondaryCpuAbiString;
- }
- return generatePackageInfo(pkg, flags, userId);
- }
- return null;
- }
-
@Override
public ApplicationInfo getApplicationInfo(String packageName, int flags, int userId) {
if (!sUserManager.exists(userId)) return null;
@@ -4932,8 +4997,10 @@
if (DEBUG_PREFERRED || debug) Slog.v(TAG, "Skipping mAlways=false entry");
continue;
}
- final ActivityInfo ai = getActivityInfo(pa.mPref.mComponent,
- flags | MATCH_DISABLED_COMPONENTS, userId);
+ final ActivityInfo ai = getActivityInfo(
+ pa.mPref.mComponent, flags | MATCH_DISABLED_COMPONENTS
+ | MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE,
+ userId);
if (DEBUG_PREFERRED || debug) {
Slog.v(TAG, "Found preferred activity:");
if (ai != null) {
@@ -5901,11 +5968,11 @@
if (listUninstalled) {
list = new ArrayList<PackageInfo>(mSettings.mPackages.size());
for (PackageSetting ps : mSettings.mPackages.values()) {
- PackageInfo pi;
+ final PackageInfo pi;
if (ps.pkg != null) {
- pi = generatePackageInfo(ps.pkg, flags, userId);
+ pi = generatePackageInfo(ps, flags, userId);
} else {
- pi = generatePackageInfoFromSettingsLPw(ps.name, flags, userId);
+ pi = generatePackageInfo(ps, flags, userId);
}
if (pi != null) {
list.add(pi);
@@ -5914,7 +5981,8 @@
} else {
list = new ArrayList<PackageInfo>(mPackages.size());
for (PackageParser.Package p : mPackages.values()) {
- PackageInfo pi = generatePackageInfo(p, flags, userId);
+ final PackageInfo pi =
+ generatePackageInfo((PackageSetting)p.mExtras, flags, userId);
if (pi != null) {
list.add(pi);
}
@@ -5941,11 +6009,11 @@
if (numMatch == 0) {
return;
}
- PackageInfo pi;
+ final PackageInfo pi;
if (ps.pkg != null) {
- pi = generatePackageInfo(ps.pkg, flags, userId);
+ pi = generatePackageInfo(ps, flags, userId);
} else {
- pi = generatePackageInfoFromSettingsLPw(ps.name, flags, userId);
+ pi = generatePackageInfo(ps, flags, userId);
}
// The above might return null in cases of uninstalled apps or install-state
// skew across users/profiles.
@@ -6914,8 +6982,8 @@
}
@Override
- public void extractPackagesIfNeeded() {
- enforceSystemOrRoot("Only the system can request package extraction");
+ public void updatePackagesIfNeeded() {
+ enforceSystemOrRoot("Only the system can request package update");
// We need to re-extract after an OTA.
boolean causeUpgrade = isUpgrade();
@@ -6946,23 +7014,15 @@
Log.i(TAG, "Extracting app " + curr + " of " + total + ": " + pkg.packageName);
}
- if (!isFirstBoot()) {
- try {
- ActivityManagerNative.getDefault().showBootMessage(
- mContext.getResources().getString(R.string.android_upgrading_apk,
- curr, total), true);
- } catch (RemoteException e) {
- }
- }
-
if (PackageDexOptimizer.canOptimizePackage(pkg)) {
// If the cache was pruned, any compiled odex files will likely be out of date
// and would have to be patched (would be SELF_PATCHOAT, which is deprecated).
// Instead, force the extraction in this case.
- performDexOpt(pkg.packageName, null /* instructionSet */,
- false /* checkProfiles */,
- causeFirstBoot ? REASON_FIRST_BOOT : REASON_BOOT,
- causePrunedCache);
+ performDexOpt(pkg.packageName,
+ null /* instructionSet */,
+ false /* checkProfiles */,
+ causeFirstBoot ? REASON_FIRST_BOOT : REASON_BOOT,
+ false /* force */);
}
}
}
@@ -7235,9 +7295,9 @@
private void deleteProfilesLI(PackageParser.Package pkg, boolean destroy) {
try {
if (destroy) {
- mInstaller.clearAppProfiles(pkg.packageName);
- } else {
mInstaller.destroyAppProfiles(pkg.packageName);
+ } else {
+ mInstaller.clearAppProfiles(pkg.packageName);
}
} catch (InstallerException ex) {
Log.e(TAG, "Could not delete profiles for package " + pkg.packageName);
@@ -9698,6 +9758,12 @@
// is granted only if it was already granted.
allowed = origPermissions.hasInstallPermission(perm);
}
+ if (!allowed && (bp.protectionLevel & PermissionInfo.PROTECTION_FLAG_SETUP) != 0
+ && pkg.packageName.equals(mSetupWizardPackage)) {
+ // If this permission is to be granted to the system setup wizard and
+ // this app is a setup wizard, then it gets the permission.
+ allowed = true;
+ }
}
return allowed;
}
@@ -9755,8 +9821,314 @@
return super.queryIntentFromList(intent, resolvedType, defaultOnly, listCut, userId);
}
+ /**
+ * Finds a privileged activity that matches the specified activity names.
+ */
+ private PackageParser.Activity findMatchingActivity(
+ List<PackageParser.Activity> activityList, ActivityInfo activityInfo) {
+ for (PackageParser.Activity sysActivity : activityList) {
+ if (sysActivity.info.name.equals(activityInfo.name)) {
+ return sysActivity;
+ }
+ if (sysActivity.info.name.equals(activityInfo.targetActivity)) {
+ return sysActivity;
+ }
+ if (sysActivity.info.targetActivity != null) {
+ if (sysActivity.info.targetActivity.equals(activityInfo.name)) {
+ return sysActivity;
+ }
+ if (sysActivity.info.targetActivity.equals(activityInfo.targetActivity)) {
+ return sysActivity;
+ }
+ }
+ }
+ return null;
+ }
+
+ public class IterGenerator<E> {
+ public Iterator<E> generate(ActivityIntentInfo info) {
+ return null;
+ }
+ }
+
+ public class ActionIterGenerator extends IterGenerator<String> {
+ @Override
+ public Iterator<String> generate(ActivityIntentInfo info) {
+ return info.actionsIterator();
+ }
+ }
+
+ public class CategoriesIterGenerator extends IterGenerator<String> {
+ @Override
+ public Iterator<String> generate(ActivityIntentInfo info) {
+ return info.categoriesIterator();
+ }
+ }
+
+ public class SchemesIterGenerator extends IterGenerator<String> {
+ @Override
+ public Iterator<String> generate(ActivityIntentInfo info) {
+ return info.schemesIterator();
+ }
+ }
+
+ public class AuthoritiesIterGenerator extends IterGenerator<IntentFilter.AuthorityEntry> {
+ @Override
+ public Iterator<IntentFilter.AuthorityEntry> generate(ActivityIntentInfo info) {
+ return info.authoritiesIterator();
+ }
+ }
+
+ /**
+ * <em>WARNING</em> for performance reasons, the passed in intentList WILL BE
+ * MODIFIED. Do not pass in a list that should not be changed.
+ */
+ private <T> void getIntentListSubset(List<ActivityIntentInfo> intentList,
+ IterGenerator<T> generator, Iterator<T> searchIterator) {
+ // loop through the set of actions; every one must be found in the intent filter
+ while (searchIterator.hasNext()) {
+ // we must have at least one filter in the list to consider a match
+ if (intentList.size() == 0) {
+ break;
+ }
+
+ final T searchAction = searchIterator.next();
+
+ // loop through the set of intent filters
+ final Iterator<ActivityIntentInfo> intentIter = intentList.iterator();
+ while (intentIter.hasNext()) {
+ final ActivityIntentInfo intentInfo = intentIter.next();
+ boolean selectionFound = false;
+
+ // loop through the intent filter's selection criteria; at least one
+ // of them must match the searched criteria
+ final Iterator<T> intentSelectionIter = generator.generate(intentInfo);
+ while (intentSelectionIter != null && intentSelectionIter.hasNext()) {
+ final T intentSelection = intentSelectionIter.next();
+ if (intentSelection != null && intentSelection.equals(searchAction)) {
+ selectionFound = true;
+ break;
+ }
+ }
+
+ // the selection criteria wasn't found in this filter's set; this filter
+ // is not a potential match
+ if (!selectionFound) {
+ intentIter.remove();
+ }
+ }
+ }
+ }
+
+ private boolean isProtectedAction(ActivityIntentInfo filter) {
+ final Iterator<String> actionsIter = filter.actionsIterator();
+ while (actionsIter != null && actionsIter.hasNext()) {
+ final String filterAction = actionsIter.next();
+ if (PROTECTED_ACTIONS.contains(filterAction)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Adjusts the priority of the given intent filter according to policy.
+ * <p>
+ * <ul>
+ * <li>The priority for non privileged applications is capped to '0'</li>
+ * <li>The priority for protected actions on privileged applications is capped to '0'</li>
+ * <li>The priority for unbundled updates to privileged applications is capped to the
+ * priority defined on the system partition</li>
+ * </ul>
+ * <p>
+ * <em>NOTE:</em> There is one exception. For security reasons, the setup wizard is
+ * allowed to obtain any priority on any action.
+ */
+ private void adjustPriority(
+ List<PackageParser.Activity> systemActivities, ActivityIntentInfo intent) {
+ // nothing to do; priority is fine as-is
+ if (intent.getPriority() <= 0) {
+ return;
+ }
+
+ final ActivityInfo activityInfo = intent.activity.info;
+ final ApplicationInfo applicationInfo = activityInfo.applicationInfo;
+
+ final boolean privilegedApp =
+ ((applicationInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0);
+ if (!privilegedApp) {
+ // non-privileged applications can never define a priority >0
+ Slog.w(TAG, "Non-privileged app; cap priority to 0;"
+ + " package: " + applicationInfo.packageName
+ + " activity: " + intent.activity.className
+ + " origPrio: " + intent.getPriority());
+ intent.setPriority(0);
+ return;
+ }
+
+ if (systemActivities == null) {
+ // the system package is not disabled; we're parsing the system partition
+ if (isProtectedAction(intent)) {
+ if (mDeferProtectedFilters) {
+ // We can't deal with these just yet. No component should ever obtain a
+ // >0 priority for a protected actions, with ONE exception -- the setup
+ // wizard. The setup wizard, however, cannot be known until we're able to
+ // query it for the category CATEGORY_SETUP_WIZARD. Which we can't do
+ // until all intent filters have been processed. Chicken, meet egg.
+ // Let the filter temporarily have a high priority and rectify the
+ // priorities after all system packages have been scanned.
+ mProtectedFilters.add(intent);
+ if (DEBUG_FILTERS) {
+ Slog.i(TAG, "Protected action; save for later;"
+ + " package: " + applicationInfo.packageName
+ + " activity: " + intent.activity.className
+ + " origPrio: " + intent.getPriority());
+ }
+ return;
+ } else {
+ if (DEBUG_FILTERS && mSetupWizardPackage == null) {
+ Slog.i(TAG, "No setup wizard;"
+ + " All protected intents capped to priority 0");
+ }
+ if (intent.activity.info.packageName.equals(mSetupWizardPackage)) {
+ if (DEBUG_FILTERS) {
+ Slog.i(TAG, "Found setup wizard;"
+ + " allow priority " + intent.getPriority() + ";"
+ + " package: " + intent.activity.info.packageName
+ + " activity: " + intent.activity.className
+ + " priority: " + intent.getPriority());
+ }
+ // setup wizard gets whatever it wants
+ return;
+ }
+ Slog.w(TAG, "Protected action; cap priority to 0;"
+ + " package: " + intent.activity.info.packageName
+ + " activity: " + intent.activity.className
+ + " origPrio: " + intent.getPriority());
+ intent.setPriority(0);
+ return;
+ }
+ }
+ // privileged apps on the system image get whatever priority they request
+ return;
+ }
+
+ // privileged app unbundled update ... try to find the same activity
+ final PackageParser.Activity foundActivity =
+ findMatchingActivity(systemActivities, activityInfo);
+ if (foundActivity == null) {
+ // this is a new activity; it cannot obtain >0 priority
+ if (DEBUG_FILTERS) {
+ Slog.i(TAG, "New activity; cap priority to 0;"
+ + " package: " + applicationInfo.packageName
+ + " activity: " + intent.activity.className
+ + " origPrio: " + intent.getPriority());
+ }
+ intent.setPriority(0);
+ return;
+ }
+
+ // found activity, now check for filter equivalence
+
+ // a shallow copy is enough; we modify the list, not its contents
+ final List<ActivityIntentInfo> intentListCopy =
+ new ArrayList<>(foundActivity.intents);
+ final List<ActivityIntentInfo> foundFilters = findFilters(intent);
+
+ // find matching action subsets
+ final Iterator<String> actionsIterator = intent.actionsIterator();
+ if (actionsIterator != null) {
+ getIntentListSubset(
+ intentListCopy, new ActionIterGenerator(), actionsIterator);
+ if (intentListCopy.size() == 0) {
+ // no more intents to match; we're not equivalent
+ if (DEBUG_FILTERS) {
+ Slog.i(TAG, "Mismatched action; cap priority to 0;"
+ + " package: " + applicationInfo.packageName
+ + " activity: " + intent.activity.className
+ + " origPrio: " + intent.getPriority());
+ }
+ intent.setPriority(0);
+ return;
+ }
+ }
+
+ // find matching category subsets
+ final Iterator<String> categoriesIterator = intent.categoriesIterator();
+ if (categoriesIterator != null) {
+ getIntentListSubset(intentListCopy, new CategoriesIterGenerator(),
+ categoriesIterator);
+ if (intentListCopy.size() == 0) {
+ // no more intents to match; we're not equivalent
+ if (DEBUG_FILTERS) {
+ Slog.i(TAG, "Mismatched category; cap priority to 0;"
+ + " package: " + applicationInfo.packageName
+ + " activity: " + intent.activity.className
+ + " origPrio: " + intent.getPriority());
+ }
+ intent.setPriority(0);
+ return;
+ }
+ }
+
+ // find matching schemes subsets
+ final Iterator<String> schemesIterator = intent.schemesIterator();
+ if (schemesIterator != null) {
+ getIntentListSubset(intentListCopy, new SchemesIterGenerator(),
+ schemesIterator);
+ if (intentListCopy.size() == 0) {
+ // no more intents to match; we're not equivalent
+ if (DEBUG_FILTERS) {
+ Slog.i(TAG, "Mismatched scheme; cap priority to 0;"
+ + " package: " + applicationInfo.packageName
+ + " activity: " + intent.activity.className
+ + " origPrio: " + intent.getPriority());
+ }
+ intent.setPriority(0);
+ return;
+ }
+ }
+
+ // find matching authorities subsets
+ final Iterator<IntentFilter.AuthorityEntry>
+ authoritiesIterator = intent.authoritiesIterator();
+ if (authoritiesIterator != null) {
+ getIntentListSubset(intentListCopy,
+ new AuthoritiesIterGenerator(),
+ authoritiesIterator);
+ if (intentListCopy.size() == 0) {
+ // no more intents to match; we're not equivalent
+ if (DEBUG_FILTERS) {
+ Slog.i(TAG, "Mismatched authority; cap priority to 0;"
+ + " package: " + applicationInfo.packageName
+ + " activity: " + intent.activity.className
+ + " origPrio: " + intent.getPriority());
+ }
+ intent.setPriority(0);
+ return;
+ }
+ }
+
+ // we found matching filter(s); app gets the max priority of all intents
+ int cappedPriority = 0;
+ for (int i = intentListCopy.size() - 1; i >= 0; --i) {
+ cappedPriority = Math.max(cappedPriority, intentListCopy.get(i).getPriority());
+ }
+ if (intent.getPriority() > cappedPriority) {
+ if (DEBUG_FILTERS) {
+ Slog.i(TAG, "Found matching filter(s);"
+ + " cap priority to " + cappedPriority + ";"
+ + " package: " + applicationInfo.packageName
+ + " activity: " + intent.activity.className
+ + " origPrio: " + intent.getPriority());
+ }
+ intent.setPriority(cappedPriority);
+ return;
+ }
+ // all this for nothing; the requested priority was <= what was on the system
+ }
+
public final void addActivity(PackageParser.Activity a, String type) {
- final boolean systemApp = a.info.applicationInfo.isSystemApp();
mActivities.put(a.getComponentName(), a);
if (DEBUG_SHOW_INFO)
Log.v(
@@ -9767,10 +10139,12 @@
final int NI = a.intents.size();
for (int j=0; j<NI; j++) {
PackageParser.ActivityIntentInfo intent = a.intents.get(j);
- if (!systemApp && intent.getPriority() > 0 && "activity".equals(type)) {
- intent.setPriority(0);
- Log.w(TAG, "Package " + a.info.applicationInfo.packageName + " has activity "
- + a.className + " with priority > 0, forcing to 0");
+ if ("activity".equals(type)) {
+ final PackageSetting ps =
+ mSettings.getDisabledSystemPkgLPr(intent.activity.info.packageName);
+ final List<PackageParser.Activity> systemActivities =
+ ps != null && ps.pkg != null ? ps.pkg.activities : null;
+ adjustPriority(systemActivities, intent);
}
if (DEBUG_SHOW_INFO) {
Log.v(TAG, " IntentFilter:");
@@ -9920,18 +10294,6 @@
out.println();
}
-// List<ResolveInfo> filterEnabled(List<ResolveInfo> resolveInfoList) {
-// final Iterator<ResolveInfo> i = resolveInfoList.iterator();
-// final List<ResolveInfo> retList = Lists.newArrayList();
-// while (i.hasNext()) {
-// final ResolveInfo resolveInfo = i.next();
-// if (isEnabledLP(resolveInfo.activityInfo)) {
-// retList.add(resolveInfo);
-// }
-// }
-// return retList;
-// }
-
// Keys are String (activity class name), values are Activity.
private final ArrayMap<ComponentName, PackageParser.Activity> mActivities
= new ArrayMap<ComponentName, PackageParser.Activity>();
@@ -10894,7 +11256,10 @@
"isPackageSuspendedForUser for user " + userId);
synchronized (mPackages) {
final PackageSetting pkgSetting = mSettings.mPackages.get(packageName);
- return pkgSetting != null && pkgSetting.getSuspended(userId);
+ if (pkgSetting == null) {
+ throw new IllegalArgumentException("Unknown target package: " + packageName);
+ }
+ return pkgSetting.getSuspended(userId);
}
}
@@ -11280,8 +11645,8 @@
* @return the current "allow unknown sources" setting
*/
private int getUnknownSourcesSettings() {
- return android.provider.Settings.Global.getInt(mContext.getContentResolver(),
- android.provider.Settings.Global.INSTALL_NON_MARKET_APPS,
+ return android.provider.Settings.Secure.getInt(mContext.getContentResolver(),
+ android.provider.Settings.Secure.INSTALL_NON_MARKET_APPS,
-1);
}
@@ -12245,8 +12610,6 @@
* Called after the source arguments are copied. This is used mostly for
* MoveParams when it needs to read the source file to put it in the
* destination.
- *
- * @return
*/
int doPostCopy(int uid) {
return PackageManager.INSTALL_SUCCEEDED;
@@ -13147,6 +13510,7 @@
final PackageParser.Package oldPackage;
final String pkgName = pkg.packageName;
final int[] allUsers;
+ final boolean weFroze;
// First find the old package info and check signatures
synchronized(mPackages) {
@@ -13179,8 +13543,32 @@
// In case of rollback, remember per-user/profile install state
allUsers = sUserManager.getUserIds();
+
+ // Mark the app as frozen to prevent launching during the upgrade
+ // process, and then kill all running instances
+ if (!ps.frozen) {
+ ps.frozen = true;
+ weFroze = true;
+ } else {
+ weFroze = false;
+ }
}
+ try {
+ replacePackageDirtyLI(pkg, oldPackage, parseFlags, scanFlags, user, allUsers,
+ installerPackageName, res);
+ } finally {
+ // Regardless of success or failure of upgrade steps above, always
+ // unfreeze the package if we froze it
+ if (weFroze) {
+ unfreezePackage(pkgName);
+ }
+ }
+ }
+
+ private void replacePackageDirtyLI(PackageParser.Package pkg, PackageParser.Package oldPackage,
+ int parseFlags, int scanFlags, UserHandle user, int[] allUsers,
+ String installerPackageName, PackageInstalledInfo res) {
// Update what is removed
res.removedInfo = new PackageRemovedInfo();
res.removedInfo.uid = oldPackage.applicationInfo.uid;
@@ -14484,7 +14872,6 @@
if (DEBUG_REMOVE) Slog.d(TAG, "deletePackageX: pkg=" + packageName + " user=" + userId);
res = deletePackageLI(packageName, removeForUser, true, allUsers,
flags | REMOVE_CHATTY, info, true, null);
- deleteProfilesLI(packageName, /*destroy*/ true);
synchronized (mPackages) {
if (res) {
mEphemeralApplicationRegistry.onPackageUninstalledLPw(uninstalledPs.pkg);
@@ -15468,17 +15855,14 @@
// Otherwise, reset the permission.
final int revokeResult = permissionsState.revokeRuntimePermission(bp, userId);
switch (revokeResult) {
- case PERMISSION_OPERATION_SUCCESS: {
- writeRuntimePermissions = true;
- } break;
-
+ case PERMISSION_OPERATION_SUCCESS:
case PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED: {
writeRuntimePermissions = true;
final int appId = ps.appId;
mHandler.post(new Runnable() {
@Override
public void run() {
- killUid(appId, userId, KILL_APP_REASON_GIDS_CHANGED);
+ killUid(appId, userId, KILL_APP_REASON_PERMISSIONS_REVOKED);
}
});
} break;
@@ -16593,6 +16977,21 @@
set, comp, userId);
}
+ private @Nullable String getSetupWizardPackageName() {
+ final Intent intent = new Intent(Intent.ACTION_MAIN);
+ intent.addCategory(Intent.CATEGORY_SETUP_WIZARD);
+
+ final List<ResolveInfo> matches = queryIntentActivitiesInternal(intent, null,
+ MATCH_SYSTEM_ONLY | MATCH_DISABLED_COMPONENTS, UserHandle.myUserId());
+ if (matches.size() == 1) {
+ return matches.get(0).getComponentInfo().packageName;
+ } else {
+ Slog.e(TAG, "There should probably be exactly one setup wizard; found " + matches.size()
+ + ": matches=" + matches);
+ return null;
+ }
+ }
+
@Override
public void setApplicationEnabledSetting(String appPackageName,
int newState, int flags, int userId, String callingPackage) {
@@ -19427,4 +19826,26 @@
return new ArrayList<>(mPackages.values());
}
}
+
+ /**
+ * Logs process start information (including base APK hash) to the security log.
+ * @hide
+ */
+ public void logAppProcessStartIfNeeded(String processName, int uid, String seinfo,
+ String apkFile, int pid) {
+ if (!SecurityLog.isLoggingEnabled()) {
+ return;
+ }
+ Bundle data = new Bundle();
+ data.putLong("startTimestamp", System.currentTimeMillis());
+ data.putString("processName", processName);
+ data.putInt("uid", uid);
+ data.putString("seinfo", seinfo);
+ data.putString("apkFile", apkFile);
+ data.putInt("pid", pid);
+ Message msg = mProcessLoggingHandler.obtainMessage(
+ ProcessLoggingHandler.LOG_APP_PROCESS_START_MSG);
+ msg.setData(data);
+ mProcessLoggingHandler.sendMessage(msg);
+ }
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceCompilerMapping.java b/services/core/java/com/android/server/pm/PackageManagerServiceCompilerMapping.java
index f1b7991..a7512db 100644
--- a/services/core/java/com/android/server/pm/PackageManagerServiceCompilerMapping.java
+++ b/services/core/java/com/android/server/pm/PackageManagerServiceCompilerMapping.java
@@ -126,4 +126,10 @@
return value;
}
+ /**
+ * Return the non-profile-guided filter corresponding to the given filter.
+ */
+ public static String getNonProfileGuidedCompilerFilter(String filter) {
+ return DexFile.getNonProfileGuidedCompilerFilter(filter);
+ }
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index bf44b0f..8527fd4 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -44,6 +44,7 @@
import android.os.Bundle;
import android.os.RemoteException;
import android.os.ShellCommand;
+import android.os.SystemProperties;
import android.os.UserHandle;
import android.text.TextUtils;
import android.util.PrintWriterPrinter;
@@ -189,7 +190,7 @@
pw.println("Package " + packageName + " new suspended state: "
+ mInterface.isPackageSuspendedForUser(packageName, userId));
return 0;
- } catch (RemoteException e) {
+ } catch (RemoteException | IllegalArgumentException e) {
pw.println(e.toString());
return 1;
}
@@ -249,31 +250,34 @@
private int runCompile() throws RemoteException {
final PrintWriter pw = getOutPrintWriter();
- boolean useJitProfiles = false;
+ boolean checkProfiles = SystemProperties.getBoolean("dalvik.vm.usejitprofiles", false);
boolean forceCompilation = false;
boolean allPackages = false;
boolean clearProfileData = false;
String compilerFilter = null;
String compilationReason = null;
+ String checkProfilesRaw = null;
if (peekNextArg() == null) {
// No arguments, show help.
pw.println("Usage: cmd package compile [-c] [-f] [--reset] [-m mode] " +
"[-r reason] [-a|pkg]");
pw.println();
- pw.println(" -c Clear profile data");
- pw.println(" -f Force compilation");
- pw.println(" --reset Reset package");
- pw.println(" -m mode Compilation mode, one of the dex2oat compiler filters");
- pw.println(" verify-none");
- pw.println(" verify-at-runtime");
- pw.println(" verify-profile");
- pw.println(" interpret-only");
- pw.println(" space-profile");
- pw.println(" space");
- pw.println(" speed-profile");
- pw.println(" speed");
- pw.println(" everything");
+ pw.println(" -c Clear profile data");
+ pw.println(" -f Force compilation");
+ pw.println(" --check-prof val Look at profiles when doing dexopt.");
+ pw.println(" Overrides dalvik.vm.usejitprofiles to true of false");
+ pw.println(" --reset Reset package");
+ pw.println(" -m mode Compilation mode, one of the dex2oat compiler filters");
+ pw.println(" verify-none");
+ pw.println(" verify-at-runtime");
+ pw.println(" verify-profile");
+ pw.println(" interpret-only");
+ pw.println(" space-profile");
+ pw.println(" space");
+ pw.println(" speed-profile");
+ pw.println(" speed");
+ pw.println(" everything");
pw.println(" -r reason Compiler reason, one of the package manager reasons");
for (int i = 0; i < PackageManagerServiceCompilerMapping.REASON_STRINGS.length; i++) {
pw.println(" " +
@@ -301,6 +305,9 @@
case "-r":
compilationReason = getNextArgRequired();
break;
+ case "-check-prof":
+ checkProfilesRaw = getNextArgRequired();
+ break;
case "--reset":
forceCompilation = true;
clearProfileData = true;
@@ -312,6 +319,17 @@
}
}
+ if (checkProfilesRaw != null) {
+ if ("true".equals(checkProfilesRaw)) {
+ checkProfiles = true;
+ } else if ("false".equals(checkProfilesRaw)) {
+ checkProfiles = false;
+ } else {
+ pw.println("Invalid value for \"--check-prof\". Expected \"true\" or \"false\".");
+ return 1;
+ }
+ }
+
if (compilerFilter != null && compilationReason != null) {
pw.println("Cannot use compilation filter (\"-m\") and compilation reason (\"-r\") " +
"at the same time");
@@ -381,7 +399,7 @@
}
boolean result = mInterface.performDexOptMode(packageName, null /* instructionSet */,
- useJitProfiles, targetCompilerFilter, forceCompilation);
+ checkProfiles, targetCompilerFilter, forceCompilation);
if (!result) {
failedPackages.add(packageName);
}
diff --git a/services/core/java/com/android/server/pm/ProcessLoggingHandler.java b/services/core/java/com/android/server/pm/ProcessLoggingHandler.java
new file mode 100644
index 0000000..c47dda4
--- /dev/null
+++ b/services/core/java/com/android/server/pm/ProcessLoggingHandler.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm;
+
+import android.app.admin.SecurityLog;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
+
+import com.android.internal.os.BackgroundThread;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.HashMap;
+import android.util.Slog;
+
+public final class ProcessLoggingHandler extends Handler {
+
+ private static final String TAG = "ProcessLoggingHandler";
+ static final int LOG_APP_PROCESS_START_MSG = 1;
+ static final int INVALIDATE_BASE_APK_HASH_MSG = 2;
+
+ private final HashMap<String, String> mProcessLoggingBaseApkHashes = new HashMap();
+
+ ProcessLoggingHandler() {
+ super(BackgroundThread.getHandler().getLooper());
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case LOG_APP_PROCESS_START_MSG: {
+ Bundle bundle = msg.getData();
+ String processName = bundle.getString("processName");
+ int uid = bundle.getInt("uid");
+ String seinfo = bundle.getString("seinfo");
+ String apkFile = bundle.getString("apkFile");
+ int pid = bundle.getInt("pid");
+ long startTimestamp = bundle.getLong("startTimestamp");
+ String apkHash = computeStringHashOfApk(apkFile);
+ SecurityLog.writeEvent(SecurityLog.TAG_APP_PROCESS_START, processName,
+ startTimestamp, uid, pid, seinfo, apkHash);
+ break;
+ }
+ case INVALIDATE_BASE_APK_HASH_MSG: {
+ Bundle bundle = msg.getData();
+ mProcessLoggingBaseApkHashes.remove(bundle.getString("apkFile"));
+ break;
+ }
+ }
+ }
+
+ void invalidateProcessLoggingBaseApkHash(String apkPath) {
+ Bundle data = new Bundle();
+ data.putString("apkFile", apkPath);
+ Message msg = obtainMessage(INVALIDATE_BASE_APK_HASH_MSG);
+ msg.setData(data);
+ sendMessage(msg);
+ }
+
+ private String computeStringHashOfApk(String apkFile) {
+ if (apkFile == null) {
+ return "No APK";
+ }
+ String apkHash = mProcessLoggingBaseApkHashes.get(apkFile);
+ if (apkHash == null) {
+ try {
+ byte[] hash = computeHashOfApkFile(apkFile);
+ StringBuilder sb = new StringBuilder();
+ for (int i = 0; i < hash.length; i++) {
+ sb.append(String.format("%02x", hash[i]));
+ }
+ apkHash = sb.toString();
+ mProcessLoggingBaseApkHashes.put(apkFile, apkHash);
+ } catch (IOException | NoSuchAlgorithmException e) {
+ Slog.w(TAG, "computeStringHashOfApk() failed", e);
+ }
+ }
+ return apkHash != null ? apkHash : "Failed to count APK hash";
+ }
+
+ private byte[] computeHashOfApkFile(String packageArchiveLocation)
+ throws IOException, NoSuchAlgorithmException {
+ MessageDigest md = MessageDigest.getInstance("SHA-256");
+ FileInputStream input = new FileInputStream(new File(packageArchiveLocation));
+ byte[] buffer = new byte[65536];
+ int size;
+ while ((size = input.read(buffer)) > 0) {
+ md.update(buffer, 0, size);
+ }
+ input.close();
+ return md.digest();
+ }
+}
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index fa0eb46..3c3c576 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -190,6 +190,7 @@
"all-intent-filter-verifications";
private static final String TAG_DEFAULT_BROWSER = "default-browser";
private static final String TAG_VERSION = "version";
+ private static final String TAG_N_WORK = "n-work";
private static final String ATTR_NAME = "name";
private static final String ATTR_USER = "user";
@@ -214,6 +215,7 @@
private static final String ATTR_VOLUME_UUID = "volumeUuid";
private static final String ATTR_SDK_VERSION = "sdkVersion";
private static final String ATTR_DATABASE_VERSION = "databaseVersion";
+ private static final String ATTR_DONE = "done";
// Bookkeeping for restored permission grants
private static final String TAG_RESTORED_RUNTIME_PERMISSIONS = "restored-perms";
@@ -386,6 +388,17 @@
public final KeySetManagerService mKeySetManagerService = new KeySetManagerService(mPackages);
+ /**
+ * Used to track whether N+ work has been done. This is similar to the file-system level
+ * and denotes that first-boot or upgrade-to-N work has been done.
+ *
+ * Note: the flag has been added to a) allow tracking while an API level check is impossible
+ * and b) to merge upgrade as well as first boot (because the flag is false, by default).
+ *
+ * STOPSHIP: b/27872764
+ */
+ private boolean mIsNWorkDone = false;
+
Settings(Object lock) {
this(Environment.getDataDirectory(), lock);
}
@@ -2327,6 +2340,10 @@
mKeySetManagerService.writeKeySetManagerServiceLPr(serializer);
+ serializer.startTag(null, TAG_N_WORK);
+ serializer.attribute(null, ATTR_DONE, Boolean.toString(mIsNWorkDone));
+ serializer.endTag(null, TAG_N_WORK);
+
serializer.endTag(null, "packages");
serializer.endDocument();
@@ -2860,7 +2877,8 @@
ver.sdkVersion = XmlUtils.readIntAttribute(parser, ATTR_SDK_VERSION);
ver.databaseVersion = XmlUtils.readIntAttribute(parser, ATTR_SDK_VERSION);
ver.fingerprint = XmlUtils.readStringAttribute(parser, ATTR_FINGERPRINT);
-
+ } else if (TAG_N_WORK.equals(tagName)) {
+ mIsNWorkDone = XmlUtils.readBooleanAttribute(parser, ATTR_DONE, false);
} else {
Slog.w(PackageManagerService.TAG, "Unknown element under <packages>: "
+ parser.getName());
@@ -4140,6 +4158,14 @@
return res;
}
+ public boolean isNWorkDone() {
+ return mIsNWorkDone;
+ }
+
+ void setNWorkDone() {
+ mIsNWorkDone = true;
+ }
+
static void printFlags(PrintWriter pw, int val, Object[] spec) {
pw.print("[ ");
for (int i=0; i<spec.length; i+=2) {
diff --git a/services/core/java/com/android/server/pm/ShortcutLauncher.java b/services/core/java/com/android/server/pm/ShortcutLauncher.java
index f1920c7..c6d66fe 100644
--- a/services/core/java/com/android/server/pm/ShortcutLauncher.java
+++ b/services/core/java/com/android/server/pm/ShortcutLauncher.java
@@ -20,6 +20,10 @@
import android.content.pm.ShortcutInfo;
import android.util.ArrayMap;
import android.util.ArraySet;
+import android.util.Slog;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.pm.ShortcutUser.PackageWithUser;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@@ -27,12 +31,13 @@
import java.io.IOException;
import java.io.PrintWriter;
+import java.util.ArrayList;
import java.util.List;
/**
* Launcher information used by {@link ShortcutService}.
*/
-class ShortcutLauncher {
+class ShortcutLauncher extends ShortcutPackageItem {
private static final String TAG = ShortcutService.TAG;
static final String TAG_ROOT = "launcher-pins";
@@ -40,38 +45,70 @@
private static final String TAG_PACKAGE = "package";
private static final String TAG_PIN = "pin";
+ private static final String ATTR_LAUNCHER_USER_ID = "launcher-user";
private static final String ATTR_VALUE = "value";
private static final String ATTR_PACKAGE_NAME = "package-name";
+ private static final String ATTR_PACKAGE_USER_ID = "package-user";
- @UserIdInt
- final int mUserId;
-
- @NonNull
- final String mPackageName;
+ private final int mOwnerUserId;
/**
* Package name -> IDs.
*/
- final private ArrayMap<String, ArraySet<String>> mPinnedShortcuts = new ArrayMap<>();
+ final private ArrayMap<PackageWithUser, ArraySet<String>> mPinnedShortcuts = new ArrayMap<>();
- ShortcutLauncher(@UserIdInt int userId, @NonNull String packageName) {
- mUserId = userId;
- mPackageName = packageName;
+ private ShortcutLauncher(@UserIdInt int ownerUserId, @NonNull String packageName,
+ @UserIdInt int launcherUserId, ShortcutPackageInfo spi) {
+ super(launcherUserId, packageName, spi != null ? spi : ShortcutPackageInfo.newEmpty());
+ mOwnerUserId = ownerUserId;
}
- public void pinShortcuts(@NonNull ShortcutService s, @NonNull String packageName,
- @NonNull List<String> ids) {
+ public ShortcutLauncher(@UserIdInt int ownerUserId, @NonNull String packageName,
+ @UserIdInt int launcherUserId) {
+ this(ownerUserId, packageName, launcherUserId, null);
+ }
+
+ @Override
+ public int getOwnerUserId() {
+ return mOwnerUserId;
+ }
+
+ /**
+ * Called when the new package can't receive the backup, due to signature or version mismatch.
+ */
+ @Override
+ protected void onRestoreBlocked(ShortcutService s) {
+ final ArrayList<PackageWithUser> pinnedPackages =
+ new ArrayList<>(mPinnedShortcuts.keySet());
+ mPinnedShortcuts.clear();
+ for (int i = pinnedPackages.size() - 1; i >= 0; i--) {
+ final PackageWithUser pu = pinnedPackages.get(i);
+ s.getPackageShortcutsLocked(pu.packageName, pu.userId)
+ .refreshPinnedFlags(s);
+ }
+ }
+
+ @Override
+ protected void onRestored(ShortcutService s) {
+ // Nothing to do.
+ }
+
+ public void pinShortcuts(@NonNull ShortcutService s, @UserIdInt int packageUserId,
+ @NonNull String packageName, @NonNull List<String> ids) {
+ final ShortcutPackage packageShortcuts =
+ s.getPackageShortcutsLocked(packageName, packageUserId);
+
+ final PackageWithUser pu = PackageWithUser.of(packageUserId, packageName);
+
final int idSize = ids.size();
if (idSize == 0) {
- mPinnedShortcuts.remove(packageName);
+ mPinnedShortcuts.remove(pu);
} else {
- final ArraySet<String> prevSet = mPinnedShortcuts.get(packageName);
+ final ArraySet<String> prevSet = mPinnedShortcuts.get(pu);
// Pin shortcuts. Make sure only pin the ones that were visible to the caller.
// i.e. a non-dynamic, pinned shortcut by *other launchers* shouldn't be pinned here.
- final ShortcutPackage packageShortcuts =
- s.getPackageShortcutsLocked(packageName, mUserId);
final ArraySet<String> newSet = new ArraySet<>();
for (int i = 0; i < idSize; i++) {
@@ -84,39 +121,49 @@
newSet.add(id);
}
}
- mPinnedShortcuts.put(packageName, newSet);
+ mPinnedShortcuts.put(pu, newSet);
}
- s.getPackageShortcutsLocked(packageName, mUserId).refreshPinnedFlags(s);
+ packageShortcuts.refreshPinnedFlags(s);
}
/**
* Return the pinned shortcut IDs for the publisher package.
*/
- public ArraySet<String> getPinnedShortcutIds(@NonNull String packageName) {
- return mPinnedShortcuts.get(packageName);
+ public ArraySet<String> getPinnedShortcutIds(@NonNull String packageName,
+ @UserIdInt int packageUserId) {
+ return mPinnedShortcuts.get(PackageWithUser.of(packageUserId, packageName));
}
- boolean cleanUpPackage(String packageName) {
- return mPinnedShortcuts.remove(packageName) != null;
+ boolean cleanUpPackage(String packageName, @UserIdInt int packageUserId) {
+ return mPinnedShortcuts.remove(PackageWithUser.of(packageUserId, packageName)) != null;
}
/**
* Persist.
*/
- public void saveToXml(XmlSerializer out) throws IOException {
+ @Override
+ public void saveToXml(XmlSerializer out, boolean forBackup)
+ throws IOException {
final int size = mPinnedShortcuts.size();
if (size == 0) {
return; // Nothing to write.
}
out.startTag(null, TAG_ROOT);
- ShortcutService.writeAttr(out, ATTR_PACKAGE_NAME,
- mPackageName);
+ ShortcutService.writeAttr(out, ATTR_PACKAGE_NAME, getPackageName());
+ ShortcutService.writeAttr(out, ATTR_LAUNCHER_USER_ID, getPackageUserId());
+ getPackageInfo().saveToXml(out);
for (int i = 0; i < size; i++) {
+ final PackageWithUser pu = mPinnedShortcuts.keyAt(i);
+
+ if (forBackup && (pu.userId != getOwnerUserId())) {
+ continue; // Target package on a different user, skip. (i.e. work profile)
+ }
+
out.startTag(null, TAG_PACKAGE);
- ShortcutService.writeAttr(out, ATTR_PACKAGE_NAME,
- mPinnedShortcuts.keyAt(i));
+ ShortcutService.writeAttr(out, ATTR_PACKAGE_NAME, pu.packageName);
+ ShortcutService.writeAttr(out, ATTR_PACKAGE_USER_ID, pu.userId);
final ArraySet<String> ids = mPinnedShortcuts.valueAt(i);
final int idSize = ids.size();
@@ -132,12 +179,18 @@
/**
* Load.
*/
- public static ShortcutLauncher loadFromXml(XmlPullParser parser, int userId)
- throws IOException, XmlPullParserException {
+ public static ShortcutLauncher loadFromXml(XmlPullParser parser, int ownerUserId,
+ boolean fromBackup) throws IOException, XmlPullParserException {
final String launcherPackageName = ShortcutService.parseStringAttribute(parser,
ATTR_PACKAGE_NAME);
- final ShortcutLauncher ret = new ShortcutLauncher(userId, launcherPackageName);
+ // If restoring, just use the real user ID.
+ final int launcherUserId =
+ fromBackup ? ownerUserId
+ : ShortcutService.parseIntAttribute(parser, ATTR_LAUNCHER_USER_ID, ownerUserId);
+
+ final ShortcutLauncher ret = new ShortcutLauncher(launcherUserId, launcherPackageName,
+ launcherUserId);
ArraySet<String> ids = null;
final int outerDepth = parser.getDepth();
@@ -149,21 +202,37 @@
}
final int depth = parser.getDepth();
final String tag = parser.getName();
- switch (tag) {
- case TAG_PACKAGE: {
- final String packageName = ShortcutService.parseStringAttribute(parser,
- ATTR_PACKAGE_NAME);
- ids = new ArraySet<>();
- ret.mPinnedShortcuts.put(packageName, ids);
- continue;
- }
- case TAG_PIN: {
- ids.add(ShortcutService.parseStringAttribute(parser,
- ATTR_VALUE));
- continue;
+ if (depth == outerDepth + 1) {
+ switch (tag) {
+ case ShortcutPackageInfo.TAG_ROOT:
+ ret.getPackageInfo().loadFromXml(parser, fromBackup);
+ continue;
+ case TAG_PACKAGE: {
+ final String packageName = ShortcutService.parseStringAttribute(parser,
+ ATTR_PACKAGE_NAME);
+ final int packageUserId = fromBackup ? ownerUserId
+ : ShortcutService.parseIntAttribute(parser,
+ ATTR_PACKAGE_USER_ID, ownerUserId);
+ ids = new ArraySet<>();
+ ret.mPinnedShortcuts.put(
+ PackageWithUser.of(packageUserId, packageName), ids);
+ continue;
+ }
}
}
- throw ShortcutService.throwForInvalidTag(depth, tag);
+ if (depth == outerDepth + 2) {
+ switch (tag) {
+ case TAG_PIN: {
+ if (ids == null) {
+ Slog.w(TAG, TAG_PIN + " in invalid place");
+ } else {
+ ids.add(ShortcutService.parseStringAttribute(parser, ATTR_VALUE));
+ }
+ continue;
+ }
+ }
+ }
+ ShortcutService.warnForInvalidTag(depth, tag);
}
return ret;
}
@@ -173,27 +242,43 @@
pw.print(prefix);
pw.print("Launcher: ");
- pw.print(mPackageName);
+ pw.print(getPackageName());
+ pw.print(" Package user: ");
+ pw.print(getPackageUserId());
+ pw.print(" Owner user: ");
+ pw.print(getOwnerUserId());
+ pw.println();
+
+ getPackageInfo().dump(s, pw, prefix + " ");
pw.println();
final int size = mPinnedShortcuts.size();
for (int i = 0; i < size; i++) {
pw.println();
+ final PackageWithUser pu = mPinnedShortcuts.keyAt(i);
+
pw.print(prefix);
pw.print(" ");
pw.print("Package: ");
- pw.println(mPinnedShortcuts.keyAt(i));
+ pw.print(pu.packageName);
+ pw.print(" User: ");
+ pw.println(pu.userId);
final ArraySet<String> ids = mPinnedShortcuts.valueAt(i);
final int idSize = ids.size();
for (int j = 0; j < idSize; j++) {
pw.print(prefix);
- pw.print(" ");
+ pw.print(" Pinned: ");
pw.print(ids.valueAt(j));
pw.println();
}
}
}
+
+ @VisibleForTesting
+ ArraySet<String> getAllPinnedShortcutsForTest(String packageName, int packageUserId) {
+ return new ArraySet<>(mPinnedShortcuts.get(PackageWithUser.of(packageUserId, packageName)));
+ }
}
diff --git a/services/core/java/com/android/server/pm/ShortcutPackage.java b/services/core/java/com/android/server/pm/ShortcutPackage.java
index d614251..1076a7a 100644
--- a/services/core/java/com/android/server/pm/ShortcutPackage.java
+++ b/services/core/java/com/android/server/pm/ShortcutPackage.java
@@ -17,7 +17,6 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.annotation.UserIdInt;
import android.content.ComponentName;
import android.content.Intent;
import android.content.pm.ShortcutInfo;
@@ -27,6 +26,8 @@
import android.util.ArraySet;
import android.util.Slog;
+import com.android.internal.annotations.VisibleForTesting;
+
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlSerializer;
@@ -35,13 +36,14 @@
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.List;
import java.util.function.Predicate;
/**
* Package information used by {@link ShortcutService}.
*/
-class ShortcutPackage {
+class ShortcutPackage extends ShortcutPackageItem {
private static final String TAG = ShortcutService.TAG;
static final String TAG_ROOT = "package";
@@ -56,6 +58,7 @@
private static final String ATTR_ID = "id";
private static final String ATTR_ACTIVITY = "activity";
private static final String ATTR_TITLE = "title";
+ private static final String ATTR_TEXT = "text";
private static final String ATTR_INTENT = "intent";
private static final String ATTR_WEIGHT = "weight";
private static final String ATTR_TIMESTAMP = "timestamp";
@@ -63,12 +66,6 @@
private static final String ATTR_ICON_RES = "icon-res";
private static final String ATTR_BITMAP_PATH = "bitmap-path";
- @UserIdInt
- final int mUserId;
-
- @NonNull
- final String mPackageName;
-
/**
* All the shortcuts from the package, keyed on IDs.
*/
@@ -89,11 +86,36 @@
*/
private long mLastResetTime;
- ShortcutPackage(int userId, String packageName) {
- mUserId = userId;
- mPackageName = packageName;
+ private ShortcutPackage(int packageUserId, String packageName, ShortcutPackageInfo spi) {
+ super(packageUserId, packageName, spi != null ? spi : ShortcutPackageInfo.newEmpty());
}
+ public ShortcutPackage(int packageUserId, String packageName) {
+ this(packageUserId, packageName, null);
+ }
+
+ @Override
+ public int getOwnerUserId() {
+ // For packages, always owner user == package user.
+ return getPackageUserId();
+ }
+
+ @Override
+ protected void onRestoreBlocked(ShortcutService s) {
+ // Can't restore due to version/signature mismatch. Remove all shortcuts.
+ mShortcuts.clear();
+ }
+
+ @Override
+ protected void onRestored(ShortcutService s) {
+ // Because some launchers may not have been restored (e.g. allowBackup=false),
+ // we need to re-calculate the pinned shortcuts.
+ refreshPinnedFlags(s);
+ }
+
+ /**
+ * Note this does *not* provide a correct view to the calling launcher.
+ */
@Nullable
public ShortcutInfo findShortcutById(String id) {
return mShortcuts.get(id);
@@ -103,7 +125,7 @@
@NonNull String id) {
final ShortcutInfo shortcut = mShortcuts.remove(id);
if (shortcut != null) {
- s.removeIcon(mUserId, shortcut);
+ s.removeIcon(getPackageUserId(), shortcut);
shortcut.clearFlags(ShortcutInfo.FLAG_DYNAMIC | ShortcutInfo.FLAG_PINNED);
}
return shortcut;
@@ -111,7 +133,7 @@
void addShortcut(@NonNull ShortcutService s, @NonNull ShortcutInfo newShortcut) {
deleteShortcut(s, newShortcut.getId());
- s.saveIconAndFixUpShortcut(mUserId, newShortcut);
+ s.saveIconAndFixUpShortcut(getPackageUserId(), newShortcut);
mShortcuts.put(newShortcut.getId(), newShortcut);
}
@@ -219,23 +241,30 @@
}
// Then, for the pinned set for each launcher, set the pin flag one by one.
- final ArrayMap<String, ShortcutLauncher> launchers =
- s.getUserShortcutsLocked(mUserId).getLaunchers();
+ final ArrayMap<ShortcutUser.PackageWithUser, ShortcutLauncher> launchers =
+ s.getUserShortcutsLocked(getPackageUserId()).getAllLaunchers();
for (int l = launchers.size() - 1; l >= 0; l--) {
+ // Note even if a launcher that hasn't been installed can still pin shortcuts.
+
final ShortcutLauncher launcherShortcuts = launchers.valueAt(l);
- final ArraySet<String> pinned = launcherShortcuts.getPinnedShortcutIds(mPackageName);
+ final ArraySet<String> pinned = launcherShortcuts.getPinnedShortcutIds(
+ getPackageName(), getPackageUserId());
if (pinned == null || pinned.size() == 0) {
continue;
}
for (int i = pinned.size() - 1; i >= 0; i--) {
- final ShortcutInfo si = mShortcuts.get(pinned.valueAt(i));
+ final String id = pinned.valueAt(i);
+ final ShortcutInfo si = mShortcuts.get(id);
if (si == null) {
- s.wtf("Shortcut not found");
- } else {
- si.addFlags(ShortcutInfo.FLAG_PINNED);
+ // This happens if a launcher pinned shortcuts from this package, then backup&
+ // restored, but this package doesn't allow backing up.
+ // In that case the launcher ends up having a dangling pinned shortcuts.
+ // That's fine, when the launcher is restored, we'll fix it.
+ continue;
}
+ si.addFlags(ShortcutInfo.FLAG_PINNED);
}
}
@@ -291,13 +320,29 @@
* Find all shortcuts that match {@code query}.
*/
public void findAll(@NonNull ShortcutService s, @NonNull List<ShortcutInfo> result,
+ @Nullable Predicate<ShortcutInfo> query, int cloneFlag) {
+ findAll(s, result, query, cloneFlag, null, 0);
+ }
+
+ /**
+ * Find all shortcuts that match {@code query}.
+ *
+ * This will also provide a "view" for each launcher -- a non-dynamic shortcut that's not pinned
+ * by the calling launcher will not be included in the result, and also "isPinned" will be
+ * adjusted for the caller too.
+ */
+ public void findAll(@NonNull ShortcutService s, @NonNull List<ShortcutInfo> result,
@Nullable Predicate<ShortcutInfo> query, int cloneFlag,
- @Nullable String callingLauncher) {
+ @Nullable String callingLauncher, int launcherUserId) {
+ if (getPackageInfo().isShadow()) {
+ // Restored and the app not installed yet, so don't return any.
+ return;
+ }
// Set of pinned shortcuts by the calling launcher.
final ArraySet<String> pinnedByCallerSet = (callingLauncher == null) ? null
- : s.getLauncherShortcuts(callingLauncher, mUserId)
- .getPinnedShortcutIds(mPackageName);
+ : s.getLauncherShortcutsLocked(callingLauncher, getPackageUserId(), launcherUserId)
+ .getPinnedShortcutIds(getPackageName(), getPackageUserId());
for (int i = 0; i < mShortcuts.size(); i++) {
final ShortcutInfo si = mShortcuts.valueAt(i);
@@ -309,7 +354,8 @@
|| ((pinnedByCallerSet != null) && pinnedByCallerSet.contains(si.getId()));
if (!si.isDynamic()) {
if (!si.isPinned()) {
- s.wtf("Shortcut not pinned here");
+ s.wtf("Shortcut not pinned: package " + getPackageName()
+ + ", user=" + getPackageUserId() + ", id=" + si.getId());
continue;
}
if (!isPinnedByCaller) {
@@ -337,7 +383,7 @@
pw.print(prefix);
pw.print("Package: ");
- pw.print(mPackageName);
+ pw.print(getPackageName());
pw.println();
pw.print(prefix);
@@ -355,6 +401,9 @@
pw.print(s.formatTime(mLastResetTime));
pw.println();
+ getPackageInfo().dump(s, pw, prefix + " ");
+ pw.println();
+
pw.println(" Shortcuts:");
long totalBitmapSize = 0;
final ArrayMap<String, ShortcutInfo> shortcuts = mShortcuts;
@@ -381,7 +430,9 @@
pw.println(")");
}
- public void saveToXml(@NonNull XmlSerializer out) throws IOException, XmlPullParserException {
+ @Override
+ public void saveToXml(@NonNull XmlSerializer out, boolean forBackup)
+ throws IOException, XmlPullParserException {
final int size = mShortcuts.size();
if (size == 0 && mApiCallCount == 0) {
@@ -390,33 +441,48 @@
out.startTag(null, TAG_ROOT);
- ShortcutService.writeAttr(out, ATTR_NAME, mPackageName);
+ ShortcutService.writeAttr(out, ATTR_NAME, getPackageName());
ShortcutService.writeAttr(out, ATTR_DYNAMIC_COUNT, mDynamicShortcutCount);
ShortcutService.writeAttr(out, ATTR_CALL_COUNT, mApiCallCount);
ShortcutService.writeAttr(out, ATTR_LAST_RESET, mLastResetTime);
+ getPackageInfo().saveToXml(out);
for (int j = 0; j < size; j++) {
- saveShortcut(out, mShortcuts.valueAt(j));
+ saveShortcut(out, mShortcuts.valueAt(j), forBackup);
}
out.endTag(null, TAG_ROOT);
}
- private static void saveShortcut(XmlSerializer out, ShortcutInfo si)
+ private static void saveShortcut(XmlSerializer out, ShortcutInfo si, boolean forBackup)
throws IOException, XmlPullParserException {
+ if (forBackup) {
+ if (!si.isPinned()) {
+ return; // Backup only pinned icons.
+ }
+ }
out.startTag(null, TAG_SHORTCUT);
ShortcutService.writeAttr(out, ATTR_ID, si.getId());
// writeAttr(out, "package", si.getPackageName()); // not needed
ShortcutService.writeAttr(out, ATTR_ACTIVITY, si.getActivityComponent());
// writeAttr(out, "icon", si.getIcon()); // We don't save it.
ShortcutService.writeAttr(out, ATTR_TITLE, si.getTitle());
+ ShortcutService.writeAttr(out, ATTR_TEXT, si.getText());
ShortcutService.writeAttr(out, ATTR_INTENT, si.getIntentNoExtras());
ShortcutService.writeAttr(out, ATTR_WEIGHT, si.getWeight());
ShortcutService.writeAttr(out, ATTR_TIMESTAMP,
si.getLastChangedTimestamp());
- ShortcutService.writeAttr(out, ATTR_FLAGS, si.getFlags());
- ShortcutService.writeAttr(out, ATTR_ICON_RES, si.getIconResourceId());
- ShortcutService.writeAttr(out, ATTR_BITMAP_PATH, si.getBitmapPath());
+ if (forBackup) {
+ // Don't write icon information. Also drop the dynamic flag.
+ ShortcutService.writeAttr(out, ATTR_FLAGS,
+ si.getFlags() &
+ ~(ShortcutInfo.FLAG_HAS_ICON_FILE | ShortcutInfo.FLAG_HAS_ICON_RES
+ | ShortcutInfo.FLAG_DYNAMIC));
+ } else {
+ ShortcutService.writeAttr(out, ATTR_FLAGS, si.getFlags());
+ ShortcutService.writeAttr(out, ATTR_ICON_RES, si.getIconResourceId());
+ ShortcutService.writeAttr(out, ATTR_BITMAP_PATH, si.getBitmapPath());
+ }
ShortcutService.writeTagExtra(out, TAG_INTENT_EXTRAS,
si.getIntentPersistableExtras());
@@ -425,13 +491,14 @@
out.endTag(null, TAG_SHORTCUT);
}
- public static ShortcutPackage loadFromXml(XmlPullParser parser, int userId)
+ public static ShortcutPackage loadFromXml(ShortcutService s, XmlPullParser parser,
+ int ownerUserId, boolean fromBackup)
throws IOException, XmlPullParserException {
final String packageName = ShortcutService.parseStringAttribute(parser,
ATTR_NAME);
- final ShortcutPackage ret = new ShortcutPackage(userId, packageName);
+ final ShortcutPackage ret = new ShortcutPackage(ownerUserId, packageName);
ret.mDynamicShortcutCount =
ShortcutService.parseIntAttribute(parser, ATTR_DYNAMIC_COUNT);
@@ -449,15 +516,20 @@
}
final int depth = parser.getDepth();
final String tag = parser.getName();
- switch (tag) {
- case TAG_SHORTCUT:
- final ShortcutInfo si = parseShortcut(parser, packageName);
+ if (depth == outerDepth + 1) {
+ switch (tag) {
+ case ShortcutPackageInfo.TAG_ROOT:
+ ret.getPackageInfo().loadFromXml(parser, fromBackup);
+ continue;
+ case TAG_SHORTCUT:
+ final ShortcutInfo si = parseShortcut(parser, packageName);
- // Don't use addShortcut(), we don't need to save the icon.
- ret.mShortcuts.put(si.getId(), si);
- continue;
+ // Don't use addShortcut(), we don't need to save the icon.
+ ret.mShortcuts.put(si.getId(), si);
+ continue;
+ }
}
- throw ShortcutService.throwForInvalidTag(depth, tag);
+ ShortcutService.warnForInvalidTag(depth, tag);
}
return ret;
}
@@ -468,6 +540,7 @@
ComponentName activityComponent;
// Icon icon;
String title;
+ String text;
Intent intent;
PersistableBundle intentPersistableExtras = null;
int weight;
@@ -481,10 +554,10 @@
activityComponent = ShortcutService.parseComponentNameAttribute(parser,
ATTR_ACTIVITY);
title = ShortcutService.parseStringAttribute(parser, ATTR_TITLE);
+ text = ShortcutService.parseStringAttribute(parser, ATTR_TEXT);
intent = ShortcutService.parseIntentAttribute(parser, ATTR_INTENT);
weight = (int) ShortcutService.parseLongAttribute(parser, ATTR_WEIGHT);
- lastChangedTimestamp = (int) ShortcutService.parseLongAttribute(parser,
- ATTR_TIMESTAMP);
+ lastChangedTimestamp = ShortcutService.parseLongAttribute(parser, ATTR_TIMESTAMP);
flags = (int) ShortcutService.parseLongAttribute(parser, ATTR_FLAGS);
iconRes = (int) ShortcutService.parseLongAttribute(parser, ATTR_ICON_RES);
bitmapPath = ShortcutService.parseStringAttribute(parser, ATTR_BITMAP_PATH);
@@ -513,8 +586,13 @@
throw ShortcutService.throwForInvalidTag(depth, tag);
}
return new ShortcutInfo(
- id, packageName, activityComponent, /* icon =*/ null, title, intent,
+ id, packageName, activityComponent, /* icon =*/ null, title, text, intent,
intentPersistableExtras, weight, extras, lastChangedTimestamp, flags,
iconRes, bitmapPath);
}
+
+ @VisibleForTesting
+ List<ShortcutInfo> getAllShortcutsForTest() {
+ return new ArrayList<>(mShortcuts.values());
+ }
}
diff --git a/services/core/java/com/android/server/pm/ShortcutPackageInfo.java b/services/core/java/com/android/server/pm/ShortcutPackageInfo.java
new file mode 100644
index 0000000..2c45890
--- /dev/null
+++ b/services/core/java/com/android/server/pm/ShortcutPackageInfo.java
@@ -0,0 +1,209 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.server.pm;
+
+import android.annotation.UserIdInt;
+import android.content.pm.PackageInfo;
+import android.util.Slog;
+
+import com.android.server.backup.BackupUtils;
+
+import libcore.io.Base64;
+import libcore.util.HexEncoding;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+
+/**
+ * Package information used by {@link android.content.pm.ShortcutManager} for backup / restore.
+ */
+class ShortcutPackageInfo {
+ private static final String TAG = ShortcutService.TAG;
+
+ static final String TAG_ROOT = "package-info";
+ private static final String ATTR_VERSION = "version";
+ private static final String ATTR_SHADOW = "shadow";
+
+ private static final String TAG_SIGNATURE = "signature";
+ private static final String ATTR_SIGNATURE_HASH = "hash";
+
+ /**
+ * When true, this package information was restored from the previous device, and the app hasn't
+ * been installed yet.
+ */
+ private boolean mIsShadow;
+ private int mVersionCode;
+ private ArrayList<byte[]> mSigHashes;
+
+ private ShortcutPackageInfo(int versionCode, ArrayList<byte[]> sigHashes, boolean isShadow) {
+ mVersionCode = versionCode;
+ mIsShadow = isShadow;
+ mSigHashes = sigHashes;
+ }
+
+ public static ShortcutPackageInfo newEmpty() {
+ return new ShortcutPackageInfo(0, new ArrayList<>(0), /* isShadow */ false);
+ }
+
+ public boolean isShadow() {
+ return mIsShadow;
+ }
+
+ public void setShadow(boolean shadow) {
+ mIsShadow = shadow;
+ }
+
+ public int getVersionCode() {
+ return mVersionCode;
+ }
+
+ public boolean hasSignatures() {
+ return mSigHashes.size() > 0;
+ }
+
+ public boolean canRestoreTo(ShortcutService s, PackageInfo target) {
+ if (!s.shouldBackupApp(target)) {
+ // "allowBackup" was true when backed up, but now false.
+ Slog.w(TAG, "Can't restore: package no longer allows backup");
+ return false;
+ }
+ if (target.versionCode < mVersionCode) {
+ Slog.w(TAG, String.format(
+ "Can't restore: package current version %d < backed up version %d",
+ target.versionCode, mVersionCode));
+ return false;
+ }
+ if (!BackupUtils.signaturesMatch(mSigHashes, target)) {
+ Slog.w(TAG, "Can't restore: Package signature mismatch");
+ return false;
+ }
+ return true;
+ }
+
+ public static ShortcutPackageInfo generateForInstalledPackage(
+ ShortcutService s, String packageName, @UserIdInt int packageUserId) {
+ final PackageInfo pi = s.getPackageInfoWithSignatures(packageName, packageUserId);
+ if (pi.signatures == null || pi.signatures.length == 0) {
+ Slog.e(TAG, "Can't get signatures: package=" + packageName);
+ return null;
+ }
+ final ShortcutPackageInfo ret = new ShortcutPackageInfo(pi.versionCode,
+ BackupUtils.hashSignatureArray(pi.signatures), /* shadow=*/ false);
+
+ return ret;
+ }
+
+ public void refresh(ShortcutService s, ShortcutPackageItem pkg) {
+ if (mIsShadow) {
+ s.wtf("Attempted to refresh package info for shadow package " + pkg.getPackageName()
+ + ", user=" + pkg.getOwnerUserId());
+ return;
+ }
+ // Note use mUserId here, rather than userId.
+ final PackageInfo pi = s.getPackageInfoWithSignatures(
+ pkg.getPackageName(), pkg.getPackageUserId());
+ if (pi == null) {
+ Slog.w(TAG, "Package not found: " + pkg.getPackageName());
+ return;
+ }
+ mVersionCode = pi.versionCode;
+ mSigHashes = BackupUtils.hashSignatureArray(pi.signatures);
+ }
+
+ public void saveToXml(XmlSerializer out) throws IOException {
+
+ out.startTag(null, TAG_ROOT);
+
+ ShortcutService.writeAttr(out, ATTR_VERSION, mVersionCode);
+ ShortcutService.writeAttr(out, ATTR_SHADOW, mIsShadow);
+
+ for (int i = 0; i < mSigHashes.size(); i++) {
+ out.startTag(null, TAG_SIGNATURE);
+ ShortcutService.writeAttr(out, ATTR_SIGNATURE_HASH, Base64.encode(mSigHashes.get(i)));
+ out.endTag(null, TAG_SIGNATURE);
+ }
+ out.endTag(null, TAG_ROOT);
+ }
+
+ public void loadFromXml(XmlPullParser parser, boolean fromBackup)
+ throws IOException, XmlPullParserException {
+
+ final int versionCode = ShortcutService.parseIntAttribute(parser, ATTR_VERSION);
+
+ // When restoring from backup, it's always shadow.
+ final boolean shadow =
+ fromBackup || ShortcutService.parseBooleanAttribute(parser, ATTR_SHADOW);
+
+ final ArrayList<byte[]> hashes = new ArrayList<>();
+
+ final int outerDepth = parser.getDepth();
+ int type;
+ while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+ && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
+ if (type != XmlPullParser.START_TAG) {
+ continue;
+ }
+ final int depth = parser.getDepth();
+ final String tag = parser.getName();
+
+ if (depth == outerDepth + 1) {
+ switch (tag) {
+ case TAG_SIGNATURE: {
+ final String hash = ShortcutService.parseStringAttribute(
+ parser, ATTR_SIGNATURE_HASH);
+ hashes.add(Base64.decode(hash.getBytes()));
+ continue;
+ }
+ }
+ }
+ ShortcutService.warnForInvalidTag(depth, tag);
+ }
+
+ // Successfully loaded; replace the feilds.
+ mVersionCode = versionCode;
+ mIsShadow = shadow;
+ mSigHashes = hashes;
+ }
+
+ public void dump(ShortcutService s, PrintWriter pw, String prefix) {
+ pw.println();
+
+ pw.print(prefix);
+ pw.println("PackageInfo:");
+
+ pw.print(prefix);
+ pw.print(" IsShadow: ");
+ pw.print(mIsShadow);
+ pw.println();
+
+ pw.print(prefix);
+ pw.print(" Version: ");
+ pw.print(mVersionCode);
+ pw.println();
+
+ for (int i = 0; i < mSigHashes.size(); i++) {
+ pw.print(prefix);
+ pw.print(" ");
+ pw.print("SigHash: ");
+ pw.println(HexEncoding.encode(mSigHashes.get(i)));
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/pm/ShortcutPackageItem.java b/services/core/java/com/android/server/pm/ShortcutPackageItem.java
new file mode 100644
index 0000000..f31dd17
--- /dev/null
+++ b/services/core/java/com/android/server/pm/ShortcutPackageItem.java
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.server.pm;
+
+import android.annotation.NonNull;
+import android.content.pm.PackageInfo;
+import android.util.Slog;
+
+import com.android.internal.util.Preconditions;
+
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+
+import java.io.IOException;
+
+abstract class ShortcutPackageItem {
+ private static final String TAG = ShortcutService.TAG;
+
+ private final int mPackageUserId;
+ private final String mPackageName;
+
+ private final ShortcutPackageInfo mPackageInfo;
+
+ protected ShortcutPackageItem(int packageUserId, @NonNull String packageName,
+ @NonNull ShortcutPackageInfo packageInfo) {
+ mPackageUserId = packageUserId;
+ mPackageName = Preconditions.checkStringNotEmpty(packageName);
+ mPackageInfo = Preconditions.checkNotNull(packageInfo);
+ }
+
+ /**
+ * ID of the user who actually has this package running on. For {@link ShortcutPackage},
+ * this is the same thing as {@link #getOwnerUserId}, but if it's a {@link ShortcutLauncher} and
+ * {@link #getOwnerUserId} is of a work profile, then this ID could be the user who owns the
+ * profile.
+ */
+ public int getPackageUserId() {
+ return mPackageUserId;
+ }
+
+ /**
+ * ID of the user who sees the shortcuts from this instance.
+ */
+ public abstract int getOwnerUserId();
+
+ @NonNull
+ public String getPackageName() {
+ return mPackageName;
+ }
+
+ public ShortcutPackageInfo getPackageInfo() {
+ return mPackageInfo;
+ }
+
+ public void refreshPackageInfoAndSave(ShortcutService s) {
+ if (mPackageInfo.isShadow()) {
+ return; // Don't refresh for shadow user.
+ }
+ mPackageInfo.refresh(s, this);
+ s.scheduleSaveUser(getOwnerUserId());
+ }
+
+ public void attemptToRestoreIfNeededAndSave(ShortcutService s) {
+ if (!mPackageInfo.isShadow()) {
+ return; // Already installed, nothing to do.
+ }
+ if (!s.isPackageInstalled(mPackageName, mPackageUserId)) {
+ if (ShortcutService.DEBUG) {
+ Slog.d(TAG, String.format("Package still not installed: %s user=%d",
+ mPackageName, mPackageUserId));
+ }
+ return; // Not installed, no need to restore yet.
+ }
+ if (!mPackageInfo.hasSignatures()) {
+ s.wtf("Attempted to restore package " + mPackageName + ", user=" + mPackageUserId
+ + " but signatures not found in the restore data.");
+ onRestoreBlocked(s);
+ return;
+ }
+
+ final PackageInfo pi = s.getPackageInfoWithSignatures(mPackageName, mPackageUserId);
+ if (!mPackageInfo.canRestoreTo(s, pi)) {
+ // Package is now installed, but can't restore. Let the subclass do the cleanup.
+ onRestoreBlocked(s);
+ return;
+ }
+ if (ShortcutService.DEBUG) {
+ Slog.d(TAG, String.format("Restored package: %s/%d on user %d", mPackageName,
+ mPackageUserId, getOwnerUserId()));
+ }
+
+ onRestored(s);
+
+ // Now the package is not shadow.
+ mPackageInfo.setShadow(false);
+
+ s.scheduleSaveUser(mPackageUserId);
+ }
+
+ /**
+ * Called when the new package can't be restored because it has a lower version number
+ * or different signatures.
+ */
+ protected abstract void onRestoreBlocked(ShortcutService s);
+
+ /**
+ * Called when the new package is successfully restored.
+ */
+ protected abstract void onRestored(ShortcutService s);
+
+ public abstract void saveToXml(@NonNull XmlSerializer out, boolean forBackup)
+ throws IOException, XmlPullParserException;
+}
diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java
index 42954f5..5c1e7a8 100644
--- a/services/core/java/com/android/server/pm/ShortcutService.java
+++ b/services/core/java/com/android/server/pm/ShortcutService.java
@@ -19,15 +19,18 @@
import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.app.ActivityManager;
+import android.app.AppGlobals;
import android.content.ComponentName;
import android.content.ContentProvider;
import android.content.Context;
import android.content.Intent;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.IPackageManager;
import android.content.pm.IShortcutService;
import android.content.pm.LauncherApps;
import android.content.pm.LauncherApps.ShortcutQuery;
+import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
-import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.PackageManagerInternal;
import android.content.pm.ParceledListSlice;
import android.content.pm.ResolveInfo;
@@ -43,6 +46,7 @@
import android.net.Uri;
import android.os.Binder;
import android.os.Environment;
+import android.os.FileUtils;
import android.os.Handler;
import android.os.Looper;
import android.os.ParcelFileDescriptor;
@@ -55,7 +59,6 @@
import android.os.UserHandle;
import android.os.UserManager;
import android.text.TextUtils;
-import android.text.format.Formatter;
import android.text.format.Time;
import android.util.ArrayMap;
import android.util.ArraySet;
@@ -74,14 +77,18 @@
import com.android.internal.util.Preconditions;
import com.android.server.LocalServices;
import com.android.server.SystemService;
+import com.android.server.pm.ShortcutUser.PackageWithUser;
import libcore.io.IoUtils;
-import libcore.util.Objects;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlSerializer;
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileDescriptor;
import java.io.FileInputStream;
@@ -89,11 +96,13 @@
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
+import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.URISyntaxException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
+import java.util.function.Consumer;
import java.util.function.Predicate;
/**
@@ -101,21 +110,14 @@
*
* - Default launcher check does take a few ms. Worth caching.
*
- * - Allow non-default launcher to start pinned shortcuts. (but not dynamic.)
- *
- * - Extract the user/package/launcher classes to their own files. Maybe rename so they all have
- * the same "Shortcut" prefix.
- *
- * - Listen to PACKAGE_*, remove orphan info, update timestamp for icon res
- * -> Need to scan all packages when a user starts too.
- * -> Clear data -> remove all dynamic? but not the pinned?
+ * - Clear data -> remove all dynamic? but not the pinned?
*
* - Scan and remove orphan bitmaps (just in case).
*
- * - Backup & restore
- *
* - Detect when already registered instances are passed to APIs again, which might break
* internal bitmap handling.
+ *
+ * - Add more call stats.
*/
public class ShortcutService extends IShortcutService.Stub {
static final String TAG = "ShortcutService";
@@ -249,12 +251,38 @@
private int mSaveDelayMillis;
+ private final IPackageManager mIPackageManager;
private final PackageManagerInternal mPackageManagerInternal;
private final UserManager mUserManager;
@GuardedBy("mLock")
private List<Integer> mDirtyUserIds = new ArrayList<>();
+ private static final int PACKAGE_MATCH_FLAGS =
+ PackageManager.MATCH_DIRECT_BOOT_AWARE
+ | PackageManager.MATCH_DIRECT_BOOT_UNAWARE
+ | PackageManager.MATCH_UNINSTALLED_PACKAGES;
+
+ // Stats
+ @VisibleForTesting
+ interface Stats {
+ int GET_DEFAULT_HOME = 0;
+ int GET_PACKAGE_INFO = 1;
+ int GET_PACKAGE_INFO_WITH_SIG = 2;
+ int GET_APPLICATION_INFO = 3;
+ int LAUNCHER_PERMISSION_CHECK = 4;
+
+ int COUNT = LAUNCHER_PERMISSION_CHECK + 1;
+ }
+
+ final Object mStatLock = new Object();
+
+ @GuardedBy("mStatLock")
+ private final int[] mCountStats = new int[Stats.COUNT];
+
+ @GuardedBy("mStatLock")
+ private final long[] mDurationStats = new long[Stats.COUNT];
+
public ShortcutService(Context context) {
this(context, BackgroundThread.get().getLooper());
}
@@ -264,12 +292,20 @@
mContext = Preconditions.checkNotNull(context);
LocalServices.addService(ShortcutServiceInternal.class, new LocalService());
mHandler = new Handler(looper);
+ mIPackageManager = AppGlobals.getPackageManager();
mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class);
mUserManager = context.getSystemService(UserManager.class);
mPackageMonitor.register(context, looper, UserHandle.ALL, /* externalStorage= */ false);
}
+ void logDurationStat(int statId, long start) {
+ synchronized (mStatLock) {
+ mCountStats[statId]++;
+ mDurationStats[statId] += (System.currentTimeMillis() - start);
+ }
+ }
+
/**
* System service lifecycle.
*/
@@ -319,6 +355,8 @@
synchronized (mLock) {
// Preload
getUserShortcutsLocked(userId);
+
+ cleanupGonePackages(userId);
}
}
@@ -434,20 +472,32 @@
return parser.getAttributeValue(null, attribute);
}
+ static boolean parseBooleanAttribute(XmlPullParser parser, String attribute) {
+ return parseLongAttribute(parser, attribute) == 1;
+ }
+
static int parseIntAttribute(XmlPullParser parser, String attribute) {
return (int) parseLongAttribute(parser, attribute);
}
+ static int parseIntAttribute(XmlPullParser parser, String attribute, int def) {
+ return (int) parseLongAttribute(parser, attribute, def);
+ }
+
static long parseLongAttribute(XmlPullParser parser, String attribute) {
+ return parseLongAttribute(parser, attribute, 0);
+ }
+
+ static long parseLongAttribute(XmlPullParser parser, String attribute, long def) {
final String value = parseStringAttribute(parser, attribute);
if (TextUtils.isEmpty(value)) {
- return 0;
+ return def;
}
try {
return Long.parseLong(value);
} catch (NumberFormatException e) {
Slog.e(TAG, "Error parsing long " + value);
- return 0;
+ return def;
}
}
@@ -510,6 +560,12 @@
writeAttr(out, name, String.valueOf(value));
}
+ static void writeAttr(XmlSerializer out, String name, boolean value) throws IOException {
+ if (value) {
+ writeAttr(out, name, "1");
+ }
+ }
+
static void writeAttr(XmlSerializer out, String name, ComponentName comp) throws IOException {
if (comp == null) return;
writeAttr(out, name, comp.flattenToString());
@@ -607,31 +663,45 @@
}
path.mkdirs();
final AtomicFile file = new AtomicFile(path);
- FileOutputStream outs = null;
+ FileOutputStream os = null;
try {
- outs = file.startWrite();
+ os = file.startWrite();
- // Write to XML
- XmlSerializer out = new FastXmlSerializer();
- out.setOutput(outs, StandardCharsets.UTF_8.name());
- out.startDocument(null, true);
+ saveUserInternalLocked(userId, os, /* forBackup= */ false);
- getUserShortcutsLocked(userId).saveToXml(out);
-
- out.endDocument();
-
- // Close.
- file.finishWrite(outs);
- } catch (IOException|XmlPullParserException e) {
+ file.finishWrite(os);
+ } catch (XmlPullParserException|IOException e) {
Slog.e(TAG, "Failed to write to file " + file.getBaseFile(), e);
- file.failWrite(outs);
+ file.failWrite(os);
}
}
+ private void saveUserInternalLocked(@UserIdInt int userId, OutputStream os,
+ boolean forBackup) throws IOException, XmlPullParserException {
+
+ final BufferedOutputStream bos = new BufferedOutputStream(os);
+
+ // Write to XML
+ XmlSerializer out = new FastXmlSerializer();
+ out.setOutput(bos, StandardCharsets.UTF_8.name());
+ out.startDocument(null, true);
+
+ getUserShortcutsLocked(userId).saveToXml(this, out, forBackup);
+
+ out.endDocument();
+
+ bos.flush();
+ os.flush();
+ }
+
static IOException throwForInvalidTag(int depth, String tag) throws IOException {
throw new IOException(String.format("Invalid tag '%s' found at depth %d", tag, depth));
}
+ static void warnForInvalidTag(int depth, String tag) throws IOException {
+ Slog.w(TAG, String.format("Invalid tag '%s' found at depth %d", tag, depth));
+ }
+
@Nullable
private ShortcutUser loadUserLocked(@UserIdInt int userId) {
final File path = new File(injectUserDataPath(userId), FILENAME_USER_PACKAGES);
@@ -649,30 +719,8 @@
}
return null;
}
- ShortcutUser ret = null;
try {
- XmlPullParser parser = Xml.newPullParser();
- parser.setInput(in, StandardCharsets.UTF_8.name());
-
- int type;
- while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) {
- if (type != XmlPullParser.START_TAG) {
- continue;
- }
- final int depth = parser.getDepth();
-
- final String tag = parser.getName();
- if (DEBUG_LOAD) {
- Slog.d(TAG, String.format("depth=%d type=%d name=%s",
- depth, type, tag));
- }
- if ((depth == 1) && ShortcutUser.TAG_ROOT.equals(tag)) {
- ret = ShortcutUser.loadFromXml(parser, userId);
- continue;
- }
- throwForInvalidTag(depth, tag);
- }
- return ret;
+ return loadUserInternal(userId, in, /* forBackup= */ false);
} catch (IOException|XmlPullParserException e) {
Slog.e(TAG, "Failed to read file " + file.getBaseFile(), e);
return null;
@@ -681,18 +729,48 @@
}
}
+ private ShortcutUser loadUserInternal(@UserIdInt int userId, InputStream is,
+ boolean fromBackup) throws XmlPullParserException, IOException {
+
+ final BufferedInputStream bis = new BufferedInputStream(is);
+
+ ShortcutUser ret = null;
+ XmlPullParser parser = Xml.newPullParser();
+ parser.setInput(bis, StandardCharsets.UTF_8.name());
+
+ int type;
+ while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) {
+ if (type != XmlPullParser.START_TAG) {
+ continue;
+ }
+ final int depth = parser.getDepth();
+
+ final String tag = parser.getName();
+ if (DEBUG_LOAD) {
+ Slog.d(TAG, String.format("depth=%d type=%d name=%s",
+ depth, type, tag));
+ }
+ if ((depth == 1) && ShortcutUser.TAG_ROOT.equals(tag)) {
+ ret = ShortcutUser.loadFromXml(this, parser, userId, fromBackup);
+ continue;
+ }
+ throwForInvalidTag(depth, tag);
+ }
+ return ret;
+ }
+
private void scheduleSaveBaseState() {
- scheduleSave(UserHandle.USER_NULL); // Special case -- use USER_NULL for base state.
+ scheduleSaveInner(UserHandle.USER_NULL); // Special case -- use USER_NULL for base state.
}
void scheduleSaveUser(@UserIdInt int userId) {
- scheduleSave(userId);
+ scheduleSaveInner(userId);
}
// In order to re-schedule, we need to reuse the same instance, so keep it in final.
private final Runnable mSaveDirtyInfoRunner = this::saveDirtyInfo;
- private void scheduleSave(@UserIdInt int userId) {
+ private void scheduleSaveInner(@UserIdInt int userId) {
if (DEBUG) {
Slog.d(TAG, "Scheduling to save for " + userId);
}
@@ -772,7 +850,7 @@
@GuardedBy("mLock")
@NonNull
- boolean isUserLoadedLocked(@UserIdInt int userId) {
+ private boolean isUserLoadedLocked(@UserIdInt int userId) {
return mUsers.get(userId) != null;
}
@@ -791,19 +869,27 @@
return userPackages;
}
+ void forEachLoadedUserLocked(@NonNull Consumer<ShortcutUser> c) {
+ for (int i = mUsers.size() - 1; i >= 0; i--) {
+ c.accept(mUsers.valueAt(i));
+ }
+ }
+
/** Return the per-user per-package state. */
@GuardedBy("mLock")
@NonNull
ShortcutPackage getPackageShortcutsLocked(
@NonNull String packageName, @UserIdInt int userId) {
- return getUserShortcutsLocked(userId).getPackageShortcuts(packageName);
+ return getUserShortcutsLocked(userId).getPackageShortcuts(this, packageName);
}
@GuardedBy("mLock")
@NonNull
- ShortcutLauncher getLauncherShortcuts(
- @NonNull String packageName, @UserIdInt int userId) {
- return getUserShortcutsLocked(userId).getLauncherShortcuts(packageName);
+ ShortcutLauncher getLauncherShortcutsLocked(
+ @NonNull String packageName, @UserIdInt int ownerUserId,
+ @UserIdInt int launcherUserId) {
+ return getUserShortcutsLocked(ownerUserId)
+ .getLauncherShortcuts(this, packageName, launcherUserId);
}
// === Caller validation ===
@@ -1016,6 +1102,10 @@
Preconditions.checkState(isCallerShell(), "Caller must be shell");
}
+ private void enforceSystem() {
+ Preconditions.checkState(isCallerSystem(), "Caller must be system");
+ }
+
private void verifyCaller(@NonNull String packageName, @UserIdInt int userId) {
Preconditions.checkStringNotEmpty(packageName, "packageName");
@@ -1035,19 +1125,6 @@
throw new SecurityException("Caller UID= doesn't own " + packageName);
}
- // Test overrides it.
- int injectGetPackageUid(@NonNull String packageName, @UserIdInt int userId) {
- try {
- return mContext.getPackageManager().getPackageUidAsUser(packageName,
- PackageManager.MATCH_DIRECT_BOOT_AWARE
- | PackageManager.MATCH_DIRECT_BOOT_UNAWARE
- | PackageManager.MATCH_UNINSTALLED_PACKAGES,
- userId);
- } catch (NameNotFoundException e) {
- return -1;
- }
- }
-
void postToHandler(Runnable r) {
mHandler.post(r);
}
@@ -1308,8 +1385,7 @@
final ArrayList<ShortcutInfo> ret = new ArrayList<>();
- getPackageShortcutsLocked(packageName, userId).findAll(this, ret, query, cloneFlags,
- /* callingLauncher= */ null);
+ getPackageShortcutsLocked(packageName, userId).findAll(this, ret, query, cloneFlags);
return new ParceledListSlice<>(ret);
}
@@ -1376,18 +1452,17 @@
@VisibleForTesting
boolean hasShortcutHostPermissionInner(@NonNull String callingPackage, int userId) {
synchronized (mLock) {
- long start = 0;
- if (DEBUG) {
- start = System.currentTimeMillis();
- }
+ final long start = System.currentTimeMillis();
final ShortcutUser user = getUserShortcutsLocked(userId);
final List<ResolveInfo> allHomeCandidates = new ArrayList<>();
// Default launcher from package manager.
+ final long startGetHomeActivitiesAsUser = System.currentTimeMillis();
final ComponentName defaultLauncher = injectPackageManagerInternal()
.getHomeActivitiesAsUser(allHomeCandidates, userId);
+ logDurationStat(Stats.GET_DEFAULT_HOME, startGetHomeActivitiesAsUser);
ComponentName detected;
if (defaultLauncher != null) {
@@ -1430,10 +1505,8 @@
lastPriority = ri.priority;
}
}
- if (DEBUG) {
- long end = System.currentTimeMillis();
- Slog.v(TAG, String.format("hasShortcutPermission took %d ms", end - start));
- }
+ logDurationStat(Stats.LAUNCHER_PERMISSION_CHECK, start);
+
if (detected != null) {
if (DEBUG) {
Slog.v(TAG, "Detected launcher: " + detected);
@@ -1449,39 +1522,53 @@
// === House keeping ===
+ /**
+ * Remove all the information associated with a package. This will really remove all the
+ * information, including the restore information (i.e. it'll remove packages even if they're
+ * shadow).
+ */
@VisibleForTesting
- void cleanUpPackageLocked(String packageName, int userId) {
- final boolean wasUserLoaded = isUserLoadedLocked(userId);
+ void cleanUpPackageLocked(String packageName, int owningUserId, int packageUserId) {
+ if (isPackageInstalled(packageName, packageUserId)) {
+ wtf("Package " + packageName + " is still installed for user " + packageUserId);
+ return;
+ }
- final ShortcutUser mUser = getUserShortcutsLocked(userId);
+ final boolean wasUserLoaded = isUserLoadedLocked(owningUserId);
+
+ final ShortcutUser mUser = getUserShortcutsLocked(owningUserId);
boolean doNotify = false;
// First, remove the package from the package list (if the package is a publisher).
- if (mUser.getPackages().remove(packageName) != null) {
- doNotify = true;
+ if (packageUserId == owningUserId) {
+ if (mUser.removePackage(packageName) != null) {
+ doNotify = true;
+ }
}
+
// Also remove from the launcher list (if the package is a launcher).
- mUser.getLaunchers().remove(packageName);
+ mUser.removeLauncher(packageUserId, packageName);
// Then remove pinned shortcuts from all launchers.
- for (int i = mUser.getLaunchers().size() - 1; i >= 0; i--) {
- mUser.getLaunchers().valueAt(i).cleanUpPackage(packageName);
+ final ArrayMap<PackageWithUser, ShortcutLauncher> launchers = mUser.getAllLaunchers();
+ for (int i = launchers.size() - 1; i >= 0; i--) {
+ launchers.valueAt(i).cleanUpPackage(packageName, packageUserId);
}
// Now there may be orphan shortcuts because we removed pinned shortucts at the previous
// step. Remove them too.
- for (int i = mUser.getPackages().size() - 1; i >= 0; i--) {
- mUser.getPackages().valueAt(i).refreshPinnedFlags(this);
+ for (int i = mUser.getAllPackages().size() - 1; i >= 0; i--) {
+ mUser.getAllPackages().valueAt(i).refreshPinnedFlags(this);
}
- scheduleSaveUser(userId);
+ scheduleSaveUser(owningUserId);
if (doNotify) {
- notifyListeners(packageName, userId);
+ notifyListeners(packageName, owningUserId);
}
if (!wasUserLoaded) {
// Note this will execute the scheduled save.
- unloadUserLocked(userId);
+ unloadUserLocked(owningUserId);
}
}
@@ -1489,8 +1576,9 @@
* Entry point from {@link LauncherApps}.
*/
private class LocalService extends ShortcutServiceInternal {
+
@Override
- public List<ShortcutInfo> getShortcuts(
+ public List<ShortcutInfo> getShortcuts(int launcherUserId,
@NonNull String callingPackage, long changedSince,
@Nullable String packageName, @Nullable ComponentName componentName,
int queryFlags, int userId) {
@@ -1501,15 +1589,18 @@
: ShortcutInfo.CLONE_REMOVE_NON_KEY_INFO;
synchronized (mLock) {
+ getLauncherShortcutsLocked(callingPackage, userId, launcherUserId)
+ .attemptToRestoreIfNeededAndSave(ShortcutService.this);
+
if (packageName != null) {
- getShortcutsInnerLocked(
+ getShortcutsInnerLocked(launcherUserId,
callingPackage, packageName, changedSince,
componentName, queryFlags, userId, ret, cloneFlag);
} else {
final ArrayMap<String, ShortcutPackage> packages =
- getUserShortcutsLocked(userId).getPackages();
+ getUserShortcutsLocked(userId).getAllPackages();
for (int i = packages.size() - 1; i >= 0; i--) {
- getShortcutsInnerLocked(
+ getShortcutsInnerLocked(launcherUserId,
callingPackage, packages.keyAt(i), changedSince,
componentName, queryFlags, userId, ret, cloneFlag);
}
@@ -1518,7 +1609,7 @@
return ret;
}
- private void getShortcutsInnerLocked(@NonNull String callingPackage,
+ private void getShortcutsInnerLocked(int launcherUserId, @NonNull String callingPackage,
@Nullable String packageName,long changedSince,
@Nullable ComponentName componentName, int queryFlags,
int userId, ArrayList<ShortcutInfo> ret, int cloneFlag) {
@@ -1538,11 +1629,11 @@
((queryFlags & ShortcutQuery.FLAG_GET_PINNED) != 0)
&& si.isPinned();
return matchDynamic || matchPinned;
- }, cloneFlag, callingPackage);
+ }, cloneFlag, callingPackage, launcherUserId);
}
@Override
- public List<ShortcutInfo> getShortcutInfo(
+ public List<ShortcutInfo> getShortcutInfo(int launcherUserId,
@NonNull String callingPackage,
@NonNull String packageName, @Nullable List<String> ids, int userId) {
// Calling permission must be checked by LauncherAppsImpl.
@@ -1551,40 +1642,86 @@
final ArrayList<ShortcutInfo> ret = new ArrayList<>(ids.size());
final ArraySet<String> idSet = new ArraySet<>(ids);
synchronized (mLock) {
+ getLauncherShortcutsLocked(callingPackage, userId, launcherUserId)
+ .attemptToRestoreIfNeededAndSave(ShortcutService.this);
+
getPackageShortcutsLocked(packageName, userId).findAll(
ShortcutService.this, ret,
(ShortcutInfo si) -> idSet.contains(si.getId()),
- ShortcutInfo.CLONE_REMOVE_FOR_LAUNCHER, callingPackage);
+ ShortcutInfo.CLONE_REMOVE_FOR_LAUNCHER, callingPackage, launcherUserId);
}
return ret;
}
@Override
- public void pinShortcuts(@NonNull String callingPackage, @NonNull String packageName,
+ public boolean isPinnedByCaller(int launcherUserId, @NonNull String callingPackage,
+ @NonNull String packageName, @NonNull String shortcutId, int userId) {
+ Preconditions.checkStringNotEmpty(packageName, "packageName");
+ Preconditions.checkStringNotEmpty(shortcutId, "shortcutId");
+
+ synchronized (mLock) {
+ getLauncherShortcutsLocked(callingPackage, userId, launcherUserId)
+ .attemptToRestoreIfNeededAndSave(ShortcutService.this);
+
+ final ShortcutInfo si = getShortcutInfoLocked(
+ launcherUserId, callingPackage, packageName, shortcutId, userId);
+ return si != null && si.isPinned();
+ }
+ }
+
+ private ShortcutInfo getShortcutInfoLocked(
+ int launcherUserId, @NonNull String callingPackage,
+ @NonNull String packageName, @NonNull String shortcutId, int userId) {
+ Preconditions.checkStringNotEmpty(packageName, "packageName");
+ Preconditions.checkStringNotEmpty(shortcutId, "shortcutId");
+
+ final ArrayList<ShortcutInfo> list = new ArrayList<>(1);
+ getPackageShortcutsLocked(packageName, userId).findAll(
+ ShortcutService.this, list,
+ (ShortcutInfo si) -> shortcutId.equals(si.getId()),
+ /* clone flags=*/ 0, callingPackage, launcherUserId);
+ return list.size() == 0 ? null : list.get(0);
+ }
+
+ @Override
+ public void pinShortcuts(int launcherUserId,
+ @NonNull String callingPackage, @NonNull String packageName,
@NonNull List<String> shortcutIds, int userId) {
// Calling permission must be checked by LauncherAppsImpl.
Preconditions.checkStringNotEmpty(packageName, "packageName");
Preconditions.checkNotNull(shortcutIds, "shortcutIds");
synchronized (mLock) {
- getLauncherShortcuts(callingPackage, userId).pinShortcuts(
- ShortcutService.this, packageName, shortcutIds);
+ final ShortcutLauncher launcher =
+ getLauncherShortcutsLocked(callingPackage, userId, launcherUserId);
+ launcher.attemptToRestoreIfNeededAndSave(ShortcutService.this);
+
+ launcher.pinShortcuts(
+ ShortcutService.this, userId, packageName, shortcutIds);
}
userPackageChanged(packageName, userId);
}
@Override
- public Intent createShortcutIntent(@NonNull String callingPackage,
+ public Intent createShortcutIntent(int launcherUserId,
+ @NonNull String callingPackage,
@NonNull String packageName, @NonNull String shortcutId, int userId) {
// Calling permission must be checked by LauncherAppsImpl.
Preconditions.checkStringNotEmpty(packageName, "packageName can't be empty");
Preconditions.checkStringNotEmpty(shortcutId, "shortcutId can't be empty");
synchronized (mLock) {
- final ShortcutInfo fullShortcut =
- getPackageShortcutsLocked(packageName, userId)
- .findShortcutById(shortcutId);
- return fullShortcut == null ? null : fullShortcut.getIntent();
+ getLauncherShortcutsLocked(callingPackage, userId, launcherUserId)
+ .attemptToRestoreIfNeededAndSave(ShortcutService.this);
+
+ // Make sure the shortcut is actually visible to the launcher.
+ final ShortcutInfo si = getShortcutInfoLocked(
+ launcherUserId, callingPackage, packageName, shortcutId, userId);
+ // "si == null" should suffice here, but check the flags too just to make sure.
+ if (si == null || !(si.isDynamic() || si.isPinned())) {
+ return null;
+ }
+ return si.getIntent();
}
}
@@ -1596,11 +1733,15 @@
}
@Override
- public int getShortcutIconResId(@NonNull String callingPackage,
+ public int getShortcutIconResId(int launcherUserId,
+ @NonNull String callingPackage,
@NonNull ShortcutInfo shortcut, int userId) {
Preconditions.checkNotNull(shortcut, "shortcut");
synchronized (mLock) {
+ getLauncherShortcutsLocked(callingPackage, userId, launcherUserId)
+ .attemptToRestoreIfNeededAndSave(ShortcutService.this);
+
final ShortcutInfo shortcutInfo = getPackageShortcutsLocked(
shortcut.getPackageName(), userId).findShortcutById(shortcut.getId());
return (shortcutInfo != null && shortcutInfo.hasIconResource())
@@ -1609,11 +1750,15 @@
}
@Override
- public ParcelFileDescriptor getShortcutIconFd(@NonNull String callingPackage,
+ public ParcelFileDescriptor getShortcutIconFd(int launcherUserId,
+ @NonNull String callingPackage,
@NonNull ShortcutInfo shortcutIn, int userId) {
Preconditions.checkNotNull(shortcutIn, "shortcut");
synchronized (mLock) {
+ getLauncherShortcutsLocked(callingPackage, userId, launcherUserId)
+ .attemptToRestoreIfNeededAndSave(ShortcutService.this);
+
final ShortcutInfo shortcutInfo = getPackageShortcutsLocked(
shortcutIn.getPackageName(), userId).findShortcutById(shortcutIn.getId());
if (shortcutInfo == null || !shortcutInfo.hasIconFile()) {
@@ -1635,12 +1780,22 @@
}
@Override
- public boolean hasShortcutHostPermission(@NonNull String callingPackage, int userId) {
- return ShortcutService.this.hasShortcutHostPermission(callingPackage, userId);
+ public boolean hasShortcutHostPermission(int launcherUserId,
+ @NonNull String callingPackage) {
+ return ShortcutService.this.hasShortcutHostPermission(callingPackage, launcherUserId);
}
}
- private PackageMonitor mPackageMonitor = new PackageMonitor() {
+ /**
+ * Package event callbacks.
+ */
+ @VisibleForTesting
+ final PackageMonitor mPackageMonitor = new PackageMonitor() {
+ @Override
+ public void onPackageAdded(String packageName, int uid) {
+ handlePackageAdded(packageName, getChangingUserId());
+ }
+
@Override
public void onPackageUpdateFinished(String packageName, int uid) {
handlePackageUpdateFinished(packageName, getChangingUserId());
@@ -1650,38 +1805,204 @@
public void onPackageRemoved(String packageName, int uid) {
handlePackageRemoved(packageName, getChangingUserId());
}
-
- @Override
- public void onPackageRemovedAllUsers(String packageName, int uid) {
- handlePackageRemovedAllUsers(packageName, getChangingUserId());
- }
};
- void handlePackageUpdateFinished(String packageName, @UserIdInt int userId) {
+ /**
+ * Called when a user is unlocked. Check all known packages still exist, and otherwise
+ * perform cleanup.
+ */
+ @VisibleForTesting
+ void cleanupGonePackages(@UserIdInt int ownerUserId) {
if (DEBUG) {
- Slog.d(TAG, "onPackageUpdateFinished() userId=" + userId);
+ Slog.d(TAG, "cleanupGonePackages() ownerUserId=" + ownerUserId);
}
- // TODO Update the version.
- }
+ final ArrayList<PackageWithUser> gonePackages = new ArrayList<>();
- void handlePackageRemoved(String packageName, @UserIdInt int userId) {
- if (DEBUG) {
- Slog.d(TAG, "onPackageRemoved() userId=" + userId);
- }
synchronized (mLock) {
- cleanUpPackageLocked(packageName, userId);
+ final ShortcutUser user = getUserShortcutsLocked(ownerUserId);
+
+ user.forAllPackageItems(spi -> {
+ if (spi.getPackageInfo().isShadow()) {
+ return; // Don't delete shadow information.
+ }
+ if (isPackageInstalled(spi.getPackageName(), spi.getPackageUserId())) {
+ return; // Package not gone.
+ }
+ gonePackages.add(PackageWithUser.of(spi));
+ });
+ if (gonePackages.size() > 0) {
+ for (int i = gonePackages.size() - 1; i >= 0; i--) {
+ final PackageWithUser pu = gonePackages.get(i);
+ cleanUpPackageLocked(pu.packageName, ownerUserId, pu.userId);
+ }
+ }
}
}
- void handlePackageRemovedAllUsers(String packageName, @UserIdInt int userId) {
+ private void handlePackageAdded(String packageName, @UserIdInt int userId) {
if (DEBUG) {
- Slog.d(TAG, "onPackageRemovedAllUsers() userId=" + userId);
+ Slog.d(TAG, String.format("handlePackageAdded: %s user=%d", packageName, userId));
}
synchronized (mLock) {
- cleanUpPackageLocked(packageName, userId);
+ forEachLoadedUserLocked(user ->
+ user.attemptToRestoreIfNeededAndSave(this, packageName, userId));
}
+ }
- // TODO Remove from all users, which we can't if the user is locked.
+ private void handlePackageUpdateFinished(String packageName, @UserIdInt int userId) {
+ if (DEBUG) {
+ Slog.d(TAG, String.format("handlePackageUpdateFinished: %s user=%d",
+ packageName, userId));
+ }
+ synchronized (mLock) {
+ forEachLoadedUserLocked(user ->
+ user.attemptToRestoreIfNeededAndSave(this, packageName, userId));
+ }
+ }
+
+ private void handlePackageRemoved(String packageName, @UserIdInt int packageUserId) {
+ if (DEBUG) {
+ Slog.d(TAG, String.format("handlePackageRemoved: %s user=%d", packageName,
+ packageUserId));
+ }
+ synchronized (mLock) {
+ forEachLoadedUserLocked(user ->
+ cleanUpPackageLocked(packageName, user.getUserId(), packageUserId));
+ }
+ }
+
+ // === PackageManager interaction ===
+
+ PackageInfo getPackageInfoWithSignatures(String packageName, @UserIdInt int userId) {
+ return injectPackageInfo(packageName, userId, true);
+ }
+
+ int injectGetPackageUid(@NonNull String packageName, @UserIdInt int userId) {
+ final long token = injectClearCallingIdentity();
+ try {
+ return mIPackageManager.getPackageUid(packageName, PACKAGE_MATCH_FLAGS
+ , userId);
+ } catch (RemoteException e) {
+ // Shouldn't happen.
+ Slog.wtf(TAG, "RemoteException", e);
+ return -1;
+ } finally {
+ injectRestoreCallingIdentity(token);
+ }
+ }
+
+ @VisibleForTesting
+ PackageInfo injectPackageInfo(String packageName, @UserIdInt int userId,
+ boolean getSignatures) {
+ final long start = System.currentTimeMillis();
+ final long token = injectClearCallingIdentity();
+ try {
+ return mIPackageManager.getPackageInfo(packageName, PACKAGE_MATCH_FLAGS
+ | (getSignatures ? PackageManager.GET_SIGNATURES : 0)
+ , userId);
+ } catch (RemoteException e) {
+ // Shouldn't happen.
+ Slog.wtf(TAG, "RemoteException", e);
+ return null;
+ } finally {
+ injectRestoreCallingIdentity(token);
+
+ logDurationStat(
+ (getSignatures ? Stats.GET_PACKAGE_INFO_WITH_SIG : Stats.GET_PACKAGE_INFO),
+ start);
+ }
+ }
+
+ @VisibleForTesting
+ ApplicationInfo injectApplicationInfo(String packageName, @UserIdInt int userId) {
+ final long start = System.currentTimeMillis();
+ final long token = injectClearCallingIdentity();
+ try {
+ return mIPackageManager.getApplicationInfo(packageName, PACKAGE_MATCH_FLAGS, userId);
+ } catch (RemoteException e) {
+ // Shouldn't happen.
+ Slog.wtf(TAG, "RemoteException", e);
+ return null;
+ } finally {
+ injectRestoreCallingIdentity(token);
+
+ logDurationStat(Stats.GET_APPLICATION_INFO, start);
+ }
+ }
+
+ private boolean isApplicationFlagSet(String packageName, int userId, int flags) {
+ final ApplicationInfo ai = injectApplicationInfo(packageName, userId);
+ return (ai != null) && ((ai.flags & flags) == flags);
+ }
+
+ boolean isPackageInstalled(String packageName, int userId) {
+ return isApplicationFlagSet(packageName, userId, ApplicationInfo.FLAG_INSTALLED);
+ }
+
+ // === Backup & restore ===
+
+ boolean shouldBackupApp(String packageName, int userId) {
+ return isApplicationFlagSet(packageName, userId, ApplicationInfo.FLAG_ALLOW_BACKUP);
+ }
+
+ boolean shouldBackupApp(PackageInfo pi) {
+ return (pi.applicationInfo.flags & ApplicationInfo.FLAG_ALLOW_BACKUP) != 0;
+ }
+
+ @Override
+ public byte[] getBackupPayload(@UserIdInt int userId) {
+ enforceSystem();
+ if (DEBUG) {
+ Slog.d(TAG, "Backing up user " + userId);
+ }
+ synchronized (mLock) {
+ final ShortcutUser user = getUserShortcutsLocked(userId);
+ if (user == null) {
+ Slog.w(TAG, "Can't backup: user not found: id=" + userId);
+ return null;
+ }
+
+ user.forAllPackageItems(spi -> spi.refreshPackageInfoAndSave(this));
+
+ // Then save.
+ final ByteArrayOutputStream os = new ByteArrayOutputStream(32 * 1024);
+ try {
+ saveUserInternalLocked(userId, os, /* forBackup */ true);
+ } catch (XmlPullParserException|IOException e) {
+ // Shouldn't happen.
+ Slog.w(TAG, "Backup failed.", e);
+ return null;
+ }
+ return os.toByteArray();
+ }
+ }
+
+ @Override
+ public void applyRestore(byte[] payload, @UserIdInt int userId) {
+ enforceSystem();
+ if (DEBUG) {
+ Slog.d(TAG, "Restoring user " + userId);
+ }
+ final ShortcutUser user;
+ final ByteArrayInputStream is = new ByteArrayInputStream(payload);
+ try {
+ user = loadUserInternal(userId, is, /* fromBackup */ true);
+ } catch (XmlPullParserException|IOException e) {
+ Slog.w(TAG, "Restoration failed.", e);
+ return;
+ }
+ synchronized (mLock) {
+ mUsers.put(userId, user);
+
+ // Then purge all the save images.
+ final File bitmapPath = getUserBitmapFilePath(userId);
+ final boolean success = FileUtils.deleteContents(bitmapPath);
+ if (!success) {
+ Slog.w(TAG, "Failed to delete " + bitmapPath);
+ }
+
+ saveUserLocked(userId);
+ }
}
// === Dump ===
@@ -1732,9 +2053,19 @@
pw.print(" Icon format: ");
pw.print(mIconPersistFormat);
pw.print(" Icon quality: ");
- pw.print(mIconPersistQuality);
+ pw.println(mIconPersistQuality);
pw.println();
+ pw.println(" Stats:");
+ synchronized (mStatLock) {
+ final String p = " ";
+ dumpStatLS(pw, p, Stats.GET_DEFAULT_HOME, "getHomeActivities()");
+ dumpStatLS(pw, p, Stats.LAUNCHER_PERMISSION_CHECK, "Launcher permission check");
+
+ dumpStatLS(pw, p, Stats.GET_PACKAGE_INFO, "getPackageInfo()");
+ dumpStatLS(pw, p, Stats.GET_PACKAGE_INFO_WITH_SIG, "getPackageInfo(SIG)");
+ dumpStatLS(pw, p, Stats.GET_APPLICATION_INFO, "getApplicationInfo");
+ }
for (int i = 0; i < mUsers.size(); i++) {
pw.println();
@@ -1749,6 +2080,15 @@
return tobj.format("%Y-%m-%d %H:%M:%S");
}
+ private void dumpStatLS(PrintWriter pw, String prefix, int statId, String label) {
+ pw.print(prefix);
+ final int count = mCountStats[statId];
+ final long dur = mDurationStats[statId];
+ pw.println(String.format("%s: count=%d, total=%dms, avg=%.1fms",
+ label, count, dur,
+ (count == 0 ? 0 : ((double) dur) / count)));
+ }
+
// === Shell support ===
@Override
@@ -1819,6 +2159,9 @@
case "refresh-default-launcher":
handleRefreshDefaultLauncher();
break;
+ case "unload-user":
+ handleUnloadUser();
+ break;
default:
return handleDefaultCommands(cmd);
}
@@ -1856,6 +2199,10 @@
pw.println("cmd shortcut refresh-default-launcher [--user USER_ID]");
pw.println(" Refresh the cached default launcher");
pw.println();
+ pw.println("cmd shortcut unload-user [--user USER_ID]");
+ pw.println(" Unload a user from the memory");
+ pw.println(" (This should not affect any observable behavior)");
+ pw.println();
}
private int handleResetThrottling() throws CommandException {
@@ -1927,6 +2274,12 @@
clearLauncher();
showLauncher();
}
+
+ private void handleUnloadUser() throws CommandException {
+ parseOptions(/* takeUser =*/ true);
+
+ ShortcutService.this.handleCleanupUser(mUserId);
+ }
}
// === Unit test support ===
@@ -1960,9 +2313,10 @@
}
final void wtf(String message) {
- Slog.wtf(TAG, message, /* exception= */ null);
+ wtf( message, /* exception= */ null);
}
+ // Injection point.
void wtf(String message, Exception e) {
Slog.wtf(TAG, message, e);
}
@@ -2033,7 +2387,7 @@
final ShortcutUser user = mUsers.get(userId);
if (user == null) return null;
- final ShortcutPackage pkg = user.getPackages().get(packageName);
+ final ShortcutPackage pkg = user.getAllPackages().get(packageName);
if (pkg == null) return null;
return pkg.findShortcutById(shortcutId);
diff --git a/services/core/java/com/android/server/pm/ShortcutUser.java b/services/core/java/com/android/server/pm/ShortcutUser.java
index 4a6b1e4..593f607 100644
--- a/services/core/java/com/android/server/pm/ShortcutUser.java
+++ b/services/core/java/com/android/server/pm/ShortcutUser.java
@@ -19,6 +19,9 @@
import android.annotation.UserIdInt;
import android.content.ComponentName;
import android.util.ArrayMap;
+import android.util.Slog;
+
+import com.android.internal.util.Preconditions;
import libcore.util.Objects;
@@ -28,6 +31,7 @@
import java.io.IOException;
import java.io.PrintWriter;
+import java.util.function.Consumer;
/**
* User information used by {@link ShortcutService}.
@@ -40,12 +44,50 @@
private static final String ATTR_VALUE = "value";
+ static final class PackageWithUser {
+ final int userId;
+ final String packageName;
+
+ private PackageWithUser(int userId, String packageName) {
+ this.userId = userId;
+ this.packageName = Preconditions.checkNotNull(packageName);
+ }
+
+ public static PackageWithUser of(int userId, String packageName) {
+ return new PackageWithUser(userId, packageName);
+ }
+
+ public static PackageWithUser of(ShortcutPackageItem spi) {
+ return new PackageWithUser(spi.getPackageUserId(), spi.getPackageName());
+ }
+
+ @Override
+ public int hashCode() {
+ return packageName.hashCode() ^ userId;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (!(obj instanceof PackageWithUser)) {
+ return false;
+ }
+ final PackageWithUser that = (PackageWithUser) obj;
+
+ return userId == that.userId && packageName.equals(that.packageName);
+ }
+
+ @Override
+ public String toString() {
+ return String.format("{Package: %d, %s}", userId, packageName);
+ }
+ }
+
@UserIdInt
- final int mUserId;
+ private final int mUserId;
private final ArrayMap<String, ShortcutPackage> mPackages = new ArrayMap<>();
- private final ArrayMap<String, ShortcutLauncher> mLaunchers = new ArrayMap<>();
+ private final ArrayMap<PackageWithUser, ShortcutLauncher> mLaunchers = new ArrayMap<>();
private ComponentName mLauncherComponent;
@@ -53,53 +95,127 @@
mUserId = userId;
}
- public ArrayMap<String, ShortcutPackage> getPackages() {
+ public int getUserId() {
+ return mUserId;
+ }
+
+ public ArrayMap<String, ShortcutPackage> getAllPackages() {
return mPackages;
}
- public ArrayMap<String, ShortcutLauncher> getLaunchers() {
+ public ShortcutPackage removePackage(@NonNull String packageName) {
+ return mPackages.remove(packageName);
+ }
+
+ public ArrayMap<PackageWithUser, ShortcutLauncher> getAllLaunchers() {
return mLaunchers;
}
- public ShortcutPackage getPackageShortcuts(@NonNull String packageName) {
+ public void addLauncher(ShortcutLauncher launcher) {
+ mLaunchers.put(PackageWithUser.of(launcher.getPackageUserId(),
+ launcher.getPackageName()), launcher);
+ }
+
+ public ShortcutLauncher removeLauncher(
+ @UserIdInt int packageUserId, @NonNull String packageName) {
+ return mLaunchers.remove(PackageWithUser.of(packageUserId, packageName));
+ }
+
+ public ShortcutPackage getPackageShortcuts(ShortcutService s, @NonNull String packageName) {
ShortcutPackage ret = mPackages.get(packageName);
if (ret == null) {
ret = new ShortcutPackage(mUserId, packageName);
mPackages.put(packageName, ret);
+ } else {
+ ret.attemptToRestoreIfNeededAndSave(s);
}
return ret;
}
- public ShortcutLauncher getLauncherShortcuts(@NonNull String packageName) {
- ShortcutLauncher ret = mLaunchers.get(packageName);
+ public ShortcutLauncher getLauncherShortcuts(ShortcutService s, @NonNull String packageName,
+ @UserIdInt int launcherUserId) {
+ final PackageWithUser key = PackageWithUser.of(launcherUserId, packageName);
+ ShortcutLauncher ret = mLaunchers.get(key);
if (ret == null) {
- ret = new ShortcutLauncher(mUserId, packageName);
- mLaunchers.put(packageName, ret);
+ ret = new ShortcutLauncher(mUserId, packageName, launcherUserId);
+ mLaunchers.put(key, ret);
+ } else {
+ ret.attemptToRestoreIfNeededAndSave(s);
}
return ret;
}
- public void saveToXml(XmlSerializer out) throws IOException, XmlPullParserException {
+ public void forAllPackageItems(Consumer<ShortcutPackageItem> callback) {
+ {
+ final int size = mLaunchers.size();
+ for (int i = 0; i < size; i++) {
+ callback.accept(mLaunchers.valueAt(i));
+ }
+ }
+ {
+ final int size = mPackages.size();
+ for (int i = 0; i < size; i++) {
+ callback.accept(mPackages.valueAt(i));
+ }
+ }
+ }
+
+ public void forPackageItem(@NonNull String packageName, @UserIdInt int packageUserId,
+ Consumer<ShortcutPackageItem> callback) {
+ forAllPackageItems(spi -> {
+ if ((spi.getPackageUserId() == packageUserId)
+ && spi.getPackageName().equals(packageName)) {
+ callback.accept(spi);
+ }
+ });
+ }
+
+ public void attemptToRestoreIfNeededAndSave(ShortcutService s, @NonNull String packageName,
+ @UserIdInt int packageUserId) {
+ forPackageItem(packageName, packageUserId, spi -> {
+ spi.attemptToRestoreIfNeededAndSave(s);
+ });
+ }
+
+ public void saveToXml(ShortcutService s, XmlSerializer out, boolean forBackup)
+ throws IOException, XmlPullParserException {
out.startTag(null, TAG_ROOT);
ShortcutService.writeTagValue(out, TAG_LAUNCHER,
mLauncherComponent);
- final int lsize = mLaunchers.size();
- for (int i = 0; i < lsize; i++) {
- mLaunchers.valueAt(i).saveToXml(out);
+ // Can't use forEachPackageItem due to the checked exceptions.
+ {
+ final int size = mLaunchers.size();
+ for (int i = 0; i < size; i++) {
+ saveShortcutPackageItem(s, out, mLaunchers.valueAt(i), forBackup);
+ }
}
-
- final int psize = mPackages.size();
- for (int i = 0; i < psize; i++) {
- mPackages.valueAt(i).saveToXml(out);
+ {
+ final int size = mPackages.size();
+ for (int i = 0; i < size; i++) {
+ saveShortcutPackageItem(s, out, mPackages.valueAt(i), forBackup);
+ }
}
out.endTag(null, TAG_ROOT);
}
- public static ShortcutUser loadFromXml(XmlPullParser parser, int userId)
- throws IOException, XmlPullParserException {
+ private void saveShortcutPackageItem(ShortcutService s, XmlSerializer out,
+ ShortcutPackageItem spi, boolean forBackup) throws IOException, XmlPullParserException {
+ if (forBackup) {
+ if (!s.shouldBackupApp(spi.getPackageName(), spi.getPackageUserId())) {
+ return; // Don't save.
+ }
+ if (spi.getPackageUserId() != spi.getOwnerUserId()) {
+ return; // Don't save cross-user information.
+ }
+ }
+ spi.saveToXml(out, forBackup);
+ }
+
+ public static ShortcutUser loadFromXml(ShortcutService s, XmlPullParser parser, int userId,
+ boolean fromBackup) throws IOException, XmlPullParserException {
final ShortcutUser ret = new ShortcutUser(userId);
final int outerDepth = parser.getDepth();
@@ -111,29 +227,30 @@
}
final int depth = parser.getDepth();
final String tag = parser.getName();
- switch (tag) {
- case TAG_LAUNCHER: {
- ret.mLauncherComponent = ShortcutService.parseComponentNameAttribute(
- parser, ATTR_VALUE);
- continue;
- }
- case ShortcutPackage.TAG_ROOT: {
- final ShortcutPackage shortcuts = ShortcutPackage.loadFromXml(parser, userId);
- // Don't use addShortcut(), we don't need to save the icon.
- ret.getPackages().put(shortcuts.mPackageName, shortcuts);
- continue;
- }
+ if (depth == outerDepth + 1) {
+ switch (tag) {
+ case TAG_LAUNCHER: {
+ ret.mLauncherComponent = ShortcutService.parseComponentNameAttribute(
+ parser, ATTR_VALUE);
+ continue;
+ }
+ case ShortcutPackage.TAG_ROOT: {
+ final ShortcutPackage shortcuts = ShortcutPackage.loadFromXml(
+ s, parser, userId, fromBackup);
- case ShortcutLauncher.TAG_ROOT: {
- final ShortcutLauncher shortcuts =
- ShortcutLauncher.loadFromXml(parser, userId);
+ // Don't use addShortcut(), we don't need to save the icon.
+ ret.mPackages.put(shortcuts.getPackageName(), shortcuts);
+ continue;
+ }
- ret.getLaunchers().put(shortcuts.mPackageName, shortcuts);
- continue;
+ case ShortcutLauncher.TAG_ROOT: {
+ ret.addLauncher(ShortcutLauncher.loadFromXml(parser, userId, fromBackup));
+ continue;
+ }
}
}
- throw ShortcutService.throwForInvalidTag(depth, tag);
+ ShortcutService.warnForInvalidTag(depth, tag);
}
return ret;
}
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 5263c37..90d500e 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -31,7 +31,6 @@
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
-import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.UserInfo;
@@ -574,12 +573,26 @@
private void broadcastProfileAvailabilityChanges(UserHandle profileHandle,
UserHandle parentHandle, boolean inQuietMode) {
- Intent intent = new Intent(Intent.ACTION_MANAGED_PROFILE_AVAILABILITY_CHANGED);
+ Intent intent = new Intent();
+ if (inQuietMode) {
+ intent.setAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE);
+ } else {
+ intent.setAction(Intent.ACTION_MANAGED_PROFILE_AVAILABLE);
+ }
intent.putExtra(Intent.EXTRA_QUIET_MODE, inQuietMode);
intent.putExtra(Intent.EXTRA_USER, profileHandle);
intent.putExtra(Intent.EXTRA_USER_HANDLE, profileHandle.getIdentifier());
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
mContext.sendBroadcastAsUser(intent, parentHandle);
+
+ //TODO: remove once Launcher3 is updated.
+ Intent oldIntent = new Intent(Intent.ACTION_MANAGED_PROFILE_AVAILABILITY_CHANGED);
+ oldIntent.putExtra(Intent.EXTRA_QUIET_MODE, inQuietMode);
+ oldIntent.putExtra(Intent.EXTRA_USER, profileHandle);
+ oldIntent.putExtra(Intent.EXTRA_USER_HANDLE, profileHandle.getIdentifier());
+ oldIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
+ mContext.sendBroadcastAsUser(oldIntent, parentHandle);
+
}
@Override
@@ -924,12 +937,12 @@
}
// Don't call them within the mRestrictionsLock.
synchronized (mPackagesLock) {
- if (globalChanged) {
- writeUserListLP();
- }
if (localChanged) {
writeUserLP(getUserDataNoChecks(userId));
}
+ if (globalChanged) {
+ writeUserListLP();
+ }
}
synchronized (mRestrictionsLock) {
@@ -1491,8 +1504,8 @@
updateUserIds();
initDefaultGuestRestrictions();
- writeUserListLP();
writeUserLP(userData);
+ writeUserListLP();
}
private String getOwnerName() {
@@ -1542,8 +1555,10 @@
serializer.attribute(null, ATTR_CREATION_TIME, Long.toString(userInfo.creationTime));
serializer.attribute(null, ATTR_LAST_LOGGED_IN_TIME,
Long.toString(userInfo.lastLoggedInTime));
- serializer.attribute(null, ATTR_LAST_LOGGED_IN_FINGERPRINT,
- userInfo.lastLoggedInFingerprint);
+ if (userInfo.lastLoggedInFingerprint != null) {
+ serializer.attribute(null, ATTR_LAST_LOGGED_IN_FINGERPRINT,
+ userInfo.lastLoggedInFingerprint);
+ }
if (userInfo.iconPath != null) {
serializer.attribute(null, ATTR_ICON_PATH, userInfo.iconPath);
}
@@ -1599,7 +1614,7 @@
serializer.endDocument();
userFile.finishWrite(fos);
} catch (Exception ioe) {
- Slog.e(LOG_TAG, "Error writing user info " + userData.info.id + "\n" + ioe);
+ Slog.e(LOG_TAG, "Error writing user info " + userData.info.id, ioe);
userFile.failWrite(fos);
}
}
@@ -1940,10 +1955,12 @@
long now = System.currentTimeMillis();
userInfo.creationTime = (now > EPOCH_PLUS_30_YEARS) ? now : 0;
userInfo.partial = true;
+ userInfo.lastLoggedInFingerprint = Build.FINGERPRINT;
userData = new UserData();
userData.info = userInfo;
mUsers.put(userId, userData);
}
+ writeUserLP(userData);
writeUserListLP();
if (parent != null) {
if (isManagedProfile) {
@@ -2196,7 +2213,13 @@
}
private void removeUserState(final int userHandle) {
- mContext.getSystemService(StorageManager.class).destroyUserKey(userHandle);
+ try {
+ mContext.getSystemService(StorageManager.class).destroyUserKey(userHandle);
+ } catch (IllegalStateException e) {
+ // This may be simply because the user was partially created.
+ Slog.i(LOG_TAG,
+ "Destroying key for user " + userHandle + " failed, continuing anyway", e);
+ }
// Cleanup package manager settings
mPm.cleanUpUser(this, userHandle);
@@ -2211,13 +2234,13 @@
mCachedEffectiveUserRestrictions.remove(userHandle);
mDevicePolicyLocalUserRestrictions.remove(userHandle);
}
- // Remove user file
- AtomicFile userFile = new AtomicFile(new File(mUsersDir, userHandle + XML_SUFFIX));
- userFile.delete();
// Update the user list
synchronized (mPackagesLock) {
writeUserListLP();
}
+ // Remove user file
+ AtomicFile userFile = new AtomicFile(new File(mUsersDir, userHandle + XML_SUFFIX));
+ userFile.delete();
updateUserIds();
File userDir = Environment.getUserSystemDirectory(userHandle);
File renamedUserDir = Environment.getUserSystemDirectory(UserHandle.USER_NULL - userHandle);
@@ -2273,6 +2296,7 @@
if (restrictions == null || restrictions.isEmpty()) {
cleanAppRestrictionsForPackage(packageName, userId);
} else {
+ restrictions.setDefusable(true);
// Write the restrictions to XML
writeApplicationRestrictionsLP(packageName, restrictions, userId);
}
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 1645366..14d0457 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -18,7 +18,6 @@
import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID;
-import static android.app.ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID;
import static android.app.ActivityManager.StackId.HOME_STACK_ID;
import static android.content.pm.PackageManager.FEATURE_PICTURE_IN_PICTURE;
import static android.content.pm.PackageManager.FEATURE_TELEVISION;
@@ -38,7 +37,6 @@
import static android.view.WindowManagerPolicy.WindowManagerFuncs.LID_CLOSED;
import static android.view.WindowManagerPolicy.WindowManagerFuncs.LID_OPEN;
-import android.Manifest;
import android.app.ActivityManager;
import android.app.ActivityManager.StackId;
import android.app.ActivityManagerInternal;
@@ -2777,11 +2775,19 @@
int insets = mWindowManagerFuncs.getDockedDividerInsetsLw();
// If the divider is behind the navigation bar, don't animate.
- if (mNavigationBar != null
+ final Rect frame = win.getFrameLw();
+ final boolean behindNavBar = mNavigationBar != null
&& ((mNavigationBarOnBottom
- && win.getFrameLw().top + insets >= mNavigationBar.getFrameLw().top)
+ && frame.top + insets >= mNavigationBar.getFrameLw().top)
|| (!mNavigationBarOnBottom
- && win.getFrameLw().left + insets >= mNavigationBar.getFrameLw().left))) {
+ && frame.left + insets >= mNavigationBar.getFrameLw().left));
+ final boolean landscape = frame.height() > frame.width();
+ final boolean offscreenLandscape = landscape && (frame.right - insets <= 0
+ || frame.left + insets >= win.getDisplayFrameLw().right);
+ final boolean offscreenPortrait = !landscape && (frame.top - insets <= 0
+ || frame.bottom + insets >= win.getDisplayFrameLw().bottom);
+ final boolean offscreen = offscreenLandscape || offscreenPortrait;
+ if (behindNavBar || offscreen) {
return 0;
}
if (transit == TRANSIT_ENTER || transit == TRANSIT_SHOW) {
@@ -3101,10 +3107,8 @@
return -1;
}
} else if (keyCode == KeyEvent.KEYCODE_SLASH && event.isMetaPressed()) {
- if (down) {
- if (repeatCount == 0) {
- toggleKeyboardShortcutsMenu(event.getDeviceId());
- }
+ if (down && repeatCount == 0 && !isKeyguardLocked()) {
+ toggleKeyboardShortcutsMenu(event.getDeviceId());
}
} else if (keyCode == KeyEvent.KEYCODE_ASSIST) {
if (down) {
@@ -4639,7 +4643,7 @@
// TYPE_SYSTEM_ERROR is above the NavigationBar so it can't be allowed to extend over it.
// Also, we don't allow windows in multi-window mode to extend out of the screen.
if ((fl & FLAG_LAYOUT_NO_LIMITS) != 0 && attrs.type != TYPE_SYSTEM_ERROR
- && !win.inMultiWindowMode()) {
+ && !win.isInMultiWindowMode()) {
df.left = df.top = -10000;
df.right = df.bottom = 10000;
if (attrs.type != TYPE_WALLPAPER) {
@@ -6291,8 +6295,7 @@
@Override
public boolean isNavBarForcedShownLw(WindowState windowState) {
- return mForceShowSystemBars
- && !windowState.getFrameLw().equals(windowState.getDisplayFrameLw());
+ return mForceShowSystemBars;
}
@Override
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index ff5a0f9..7570960 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -538,7 +538,10 @@
@Override
public void onBootPhase(int phase) {
synchronized (mLock) {
- if (phase == PHASE_BOOT_COMPLETED) {
+ if (phase == PHASE_THIRD_PARTY_APPS_CAN_START) {
+ incrementBootCount();
+
+ } else if (phase == PHASE_BOOT_COMPLETED) {
final long now = SystemClock.uptimeMillis();
mBootCompleted = true;
mDirty |= DIRTY_BOOT_COMPLETED;
@@ -553,8 +556,6 @@
}
}
mBootCompletedRunnables = null;
-
- incrementBootCount();
}
}
}
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
index 4a00ebd..dbbaa5e 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
@@ -319,7 +319,7 @@
*/
@Override
public void disable2(int what, IBinder token, String pkg) {
- disableForUser(what, token, pkg, mCurrentUserId);
+ disable2ForUser(what, token, pkg, mCurrentUserId);
}
/**
diff --git a/services/core/java/com/android/server/vr/EnabledComponentsObserver.java b/services/core/java/com/android/server/vr/EnabledComponentsObserver.java
index 1363fb9..eb926c1 100644
--- a/services/core/java/com/android/server/vr/EnabledComponentsObserver.java
+++ b/services/core/java/com/android/server/vr/EnabledComponentsObserver.java
@@ -227,10 +227,11 @@
return userIds;
}
- private ArraySet<ComponentName> loadComponentNamesForUser(int userId) {
+ public static ArraySet<ComponentName> loadComponentNames(PackageManager pm, int userId,
+ String serviceName, String permissionName) {
+
ArraySet<ComponentName> installed = new ArraySet<>();
- PackageManager pm = mContext.getPackageManager();
- Intent queryIntent = new Intent(mServiceName);
+ Intent queryIntent = new Intent(serviceName);
List<ResolveInfo> installedServices = pm.queryIntentServicesAsUser(
queryIntent,
PackageManager.GET_SERVICES | PackageManager.GET_META_DATA,
@@ -241,10 +242,10 @@
ServiceInfo info = resolveInfo.serviceInfo;
ComponentName component = new ComponentName(info.packageName, info.name);
- if (!mServicePermission.equals(info.permission)) {
+ if (!permissionName.equals(info.permission)) {
Slog.w(TAG, "Skipping service " + info.packageName + "/" + info.name
+ ": it does not require the permission "
- + mServicePermission);
+ + permissionName);
continue;
}
installed.add(component);
@@ -253,6 +254,11 @@
return installed;
}
+ private ArraySet<ComponentName> loadComponentNamesForUser(int userId) {
+ return loadComponentNames(mContext.getPackageManager(), userId, mServiceName,
+ mServicePermission);
+ }
+
private ArraySet<ComponentName> loadComponentNamesFromSetting(String settingName,
int userId) {
final ContentResolver cr = mContext.getContentResolver();
diff --git a/services/core/java/com/android/server/vr/VrManagerService.java b/services/core/java/com/android/server/vr/VrManagerService.java
index aa6f59e..c572e76 100644
--- a/services/core/java/com/android/server/vr/VrManagerService.java
+++ b/services/core/java/com/android/server/vr/VrManagerService.java
@@ -16,16 +16,23 @@
package com.android.server.vr;
import android.app.AppOpsManager;
+import android.app.NotificationManager;
import android.annotation.NonNull;
-import android.content.Context;
import android.content.ComponentName;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
import android.os.Binder;
import android.os.Handler;
import android.os.IBinder;
import android.os.IInterface;
import android.os.Looper;
import android.os.RemoteException;
+import android.os.UserHandle;
import android.provider.Settings;
+import android.service.notification.NotificationListenerService;
import android.service.vr.IVrListener;
import android.service.vr.VrListenerService;
import android.util.ArraySet;
@@ -38,7 +45,9 @@
import com.android.server.utils.ManagedApplicationService;
import com.android.server.utils.ManagedApplicationService.BinderChecker;
+import java.lang.StringBuilder;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.Objects;
import java.util.Set;
@@ -53,8 +62,8 @@
* hardware/libhardware/modules/vr
* <p/>
* In general applications may enable or disable VR mode by calling
- * {@link android.app.Activity#setVrMode)}. An application may also implement a service to be run
- * while in VR mode by implementing {@link android.service.vr.VrListenerService}.
+ * {@link android.app.Activity#setVrModeEnabled)}. An application may also implement a service to
+ * be run while in VR mode by implementing {@link android.service.vr.VrListenerService}.
*
* @see {@link android.service.vr.VrListenerService}
* @see {@link com.android.server.vr.VrManagerInternal}
@@ -74,13 +83,18 @@
private final IBinder mOverlayToken = new Binder();
// State protected by mLock
- private boolean mVrModeEnabled = false;
+ private boolean mVrModeEnabled;
private final Set<VrStateListener> mListeners = new ArraySet<>();
private EnabledComponentsObserver mComponentObserver;
private ManagedApplicationService mCurrentVrService;
private Context mContext;
private ComponentName mCurrentVrModeComponent;
private int mCurrentVrModeUser;
+ private boolean mWasDefaultGranted;
+ private boolean mGuard;
+ private final ArraySet<String> mPreviousToggledListenerSettings = new ArraySet<>();
+ private String mPreviousNotificationPolicyAccessPackage;
+ private String mPreviousManageOverlayPackage;
private static final BinderChecker sBinderChecker = new BinderChecker() {
@Override
@@ -239,62 +253,271 @@
*
* @return {@code true} if the component/user combination specified is valid.
*/
- private boolean updateCurrentVrServiceLocked(boolean enabled,
- @NonNull ComponentName component, int userId, ComponentName calling) {
+ private boolean updateCurrentVrServiceLocked(boolean enabled, @NonNull ComponentName component,
+ int userId, ComponentName calling) {
boolean sendUpdatedCaller = false;
+ final long identity = Binder.clearCallingIdentity();
+ try {
- boolean validUserComponent = (mComponentObserver.isValid(component, userId) ==
- EnabledComponentsObserver.NO_ERROR);
+ boolean validUserComponent = (mComponentObserver.isValid(component, userId) ==
+ EnabledComponentsObserver.NO_ERROR);
- // Always send mode change events.
- changeVrModeLocked(enabled, (enabled && validUserComponent) ? component : null);
+ // Always send mode change events.
+ changeVrModeLocked(enabled, (enabled && validUserComponent) ? component : null);
- if (!enabled || !validUserComponent) {
- // Unbind whatever is running
- if (mCurrentVrService != null) {
- Slog.i(TAG, "Disconnecting " + mCurrentVrService.getComponent() + " for user " +
- mCurrentVrService.getUserId());
- mCurrentVrService.disconnect();
- mCurrentVrService = null;
- }
- } else {
- if (mCurrentVrService != null) {
- // Unbind any running service that doesn't match the component/user selection
- if (mCurrentVrService.disconnectIfNotMatching(component, userId)) {
+ if (!enabled || !validUserComponent) {
+ // Unbind whatever is running
+ if (mCurrentVrService != null) {
Slog.i(TAG, "Disconnecting " + mCurrentVrService.getComponent() + " for user " +
- mCurrentVrService.getUserId());
+ mCurrentVrService.getUserId());
+ mCurrentVrService.disconnect();
+ disableImpliedPermissionsLocked(mCurrentVrService.getComponent(),
+ new UserHandle(mCurrentVrService.getUserId()));
+ mCurrentVrService = null;
+ }
+ } else {
+ if (mCurrentVrService != null) {
+ // Unbind any running service that doesn't match the component/user selection
+ if (mCurrentVrService.disconnectIfNotMatching(component, userId)) {
+ Slog.i(TAG, "Disconnecting " + mCurrentVrService.getComponent() +
+ " for user " + mCurrentVrService.getUserId());
+ disableImpliedPermissionsLocked(mCurrentVrService.getComponent(),
+ new UserHandle(mCurrentVrService.getUserId()));
+ createAndConnectService(component, userId);
+ enableImpliedPermissionsLocked(mCurrentVrService.getComponent(),
+ new UserHandle(mCurrentVrService.getUserId()));
+ sendUpdatedCaller = true;
+ }
+ // The service with the correct component/user is bound
+ } else {
+ // Nothing was previously running, bind a new service
createAndConnectService(component, userId);
+ enableImpliedPermissionsLocked(mCurrentVrService.getComponent(),
+ new UserHandle(mCurrentVrService.getUserId()));
sendUpdatedCaller = true;
}
- // The service with the correct component/user is bound
- } else {
- // Nothing was previously running, bind a new service
- createAndConnectService(component, userId);
+ }
+
+ if (calling != null && !Objects.equals(calling, mCurrentVrModeComponent)) {
+ mCurrentVrModeComponent = calling;
+ mCurrentVrModeUser = userId;
sendUpdatedCaller = true;
}
+
+ if (mCurrentVrService != null && sendUpdatedCaller) {
+ final ComponentName c = mCurrentVrModeComponent;
+ mCurrentVrService.sendEvent(new PendingEvent() {
+ @Override
+ public void runEvent(IInterface service) throws RemoteException {
+ IVrListener l = (IVrListener) service;
+ l.focusedActivityChanged(c);
+ }
+ });
+ }
+
+ return validUserComponent;
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
+ /**
+ * Enable the permission given in {@link #IMPLIED_VR_LISTENER_PERMISSIONS} for the given
+ * component package and user.
+ *
+ * @param component the component whose package should be enabled.
+ * @param userId the user that owns the given component.
+ */
+ private void enableImpliedPermissionsLocked(ComponentName component, UserHandle userId) {
+ if (mGuard) {
+ // Impossible
+ throw new IllegalStateException("Enabling permissions without disabling.");
+ }
+ mGuard = true;
+
+ PackageManager pm = mContext.getPackageManager();
+
+ String pName = component.getPackageName();
+ if (pm == null) {
+ Slog.e(TAG, "Couldn't set implied permissions for " + pName +
+ ", PackageManager isn't running");
+ return;
+ }
+
+ ApplicationInfo info = null;
+ try {
+ info = pm.getApplicationInfo(pName, PackageManager.GET_META_DATA);
+ } catch (NameNotFoundException e) {
+ }
+
+ if (info == null) {
+ Slog.e(TAG, "Couldn't set implied permissions for " + pName + ", no such package.");
+ return;
+ }
+
+ if (!(info.isSystemApp() || info.isUpdatedSystemApp())) {
+ return; // Application is not pre-installed, avoid setting implied permissions
+ }
+
+ mWasDefaultGranted = true;
+
+ grantOverlayAccess(pName, userId);
+ grantNotificationPolicyAccess(pName);
+ grantNotificationListenerAccess(pName, userId);
+ }
+
+ /**
+ * Disable the permission given in {@link #IMPLIED_VR_LISTENER_PERMISSIONS} for the given
+ * component package and user.
+ *
+ * @param component the component whose package should be disabled.
+ * @param userId the user that owns the given component.
+ */
+ private void disableImpliedPermissionsLocked(ComponentName component, UserHandle userId) {
+ if (!mGuard) {
+ // Impossible
+ throw new IllegalStateException("Disabling permissions without enabling.");
+ }
+ mGuard = false;
+
+ PackageManager pm = mContext.getPackageManager();
+
+ if (pm == null) {
+ Slog.e(TAG, "Couldn't remove implied permissions for " + component +
+ ", PackageManager isn't running");
+ return;
+ }
+
+ String pName = component.getPackageName();
+ if (mWasDefaultGranted) {
+ revokeOverlayAccess(userId);
+ revokeNotificationPolicyAccess(pName);
+ revokeNotificiationListenerAccess();
+ mWasDefaultGranted = false;
+ }
+
+ }
+
+ private void grantOverlayAccess(String pkg, UserHandle userId) {
+ PackageManager pm = mContext.getPackageManager();
+ boolean prev = (PackageManager.PERMISSION_GRANTED ==
+ pm.checkPermission(android.Manifest.permission.SYSTEM_ALERT_WINDOW, pkg));
+ mPreviousManageOverlayPackage = null;
+ if (!prev) {
+ pm.grantRuntimePermission(pkg, android.Manifest.permission.SYSTEM_ALERT_WINDOW,
+ userId);
+ mPreviousManageOverlayPackage = pkg;
+ }
+ }
+
+ private void revokeOverlayAccess(UserHandle userId) {
+ PackageManager pm = mContext.getPackageManager();
+ if (mPreviousManageOverlayPackage != null) {
+ pm.revokeRuntimePermission(mPreviousManageOverlayPackage,
+ android.Manifest.permission.SYSTEM_ALERT_WINDOW, userId);
+ mPreviousManageOverlayPackage = null;
+ }
+ }
+
+
+ private void grantNotificationPolicyAccess(String pkg) {
+ NotificationManager nm = mContext.getSystemService(NotificationManager.class);
+ boolean prev = nm.isNotificationPolicyAccessGrantedForPackage(pkg);
+ mPreviousNotificationPolicyAccessPackage = null;
+ if (!prev) {
+ mPreviousNotificationPolicyAccessPackage = pkg;
+ nm.setNotificationPolicyAccessGranted(pkg, true);
+ }
+ }
+
+ private void revokeNotificationPolicyAccess(String pkg) {
+ NotificationManager nm = mContext.getSystemService(NotificationManager.class);
+ if (mPreviousNotificationPolicyAccessPackage != null) {
+ nm.setNotificationPolicyAccessGranted(mPreviousNotificationPolicyAccessPackage, false);
+ mPreviousNotificationPolicyAccessPackage = null;
+ }
+ }
+
+ private void grantNotificationListenerAccess(String pkg, UserHandle userId) {
+ PackageManager pm = mContext.getPackageManager();
+ ArraySet<ComponentName> possibleServices = EnabledComponentsObserver.loadComponentNames(pm,
+ userId.getIdentifier(), NotificationListenerService.SERVICE_INTERFACE,
+ android.Manifest.permission.BIND_NOTIFICATION_LISTENER_SERVICE);
+ ContentResolver resolver = mContext.getContentResolver();
+
+ ArraySet<String> current = getCurrentNotifListeners(resolver);
+
+ mPreviousToggledListenerSettings.clear();
+
+ for (ComponentName c : possibleServices) {
+ String flatName = c.flattenToString();
+ if (Objects.equals(c.getPackageName(), pkg)
+ && !current.contains(flatName)) {
+ mPreviousToggledListenerSettings.add(flatName);
+ current.add(flatName);
+ }
}
- if (calling != null && !Objects.equals(calling, mCurrentVrModeComponent)) {
- mCurrentVrModeComponent = calling;
- mCurrentVrModeUser = userId;
- sendUpdatedCaller = true;
+ if (current.size() > 0) {
+ String flatSettings = formatSettings(current);
+ Settings.Secure.putString(resolver, Settings.Secure.ENABLED_NOTIFICATION_LISTENERS,
+ flatSettings);
}
-
- if (mCurrentVrService != null && sendUpdatedCaller) {
- final ComponentName c = mCurrentVrModeComponent;
- mCurrentVrService.sendEvent(new PendingEvent() {
- @Override
- public void runEvent(IInterface service) throws RemoteException {
- IVrListener l = (IVrListener) service;
- l.focusedActivityChanged(c);
- }
- });
- }
-
- return validUserComponent;
}
+ private void revokeNotificiationListenerAccess() {
+ if (mPreviousToggledListenerSettings.isEmpty()) {
+ return;
+ }
+
+ ContentResolver resolver = mContext.getContentResolver();
+ ArraySet<String> current = getCurrentNotifListeners(resolver);
+
+ current.removeAll(mPreviousToggledListenerSettings);
+ mPreviousToggledListenerSettings.clear();
+
+ String flatSettings = formatSettings(current);
+ Settings.Secure.putString(resolver, Settings.Secure.ENABLED_NOTIFICATION_LISTENERS,
+ flatSettings);
+ }
+
+ private ArraySet<String> getCurrentNotifListeners(ContentResolver resolver) {
+ String flat = Settings.Secure.getString(resolver,
+ Settings.Secure.ENABLED_NOTIFICATION_LISTENERS);
+
+ ArraySet<String> current = new ArraySet<>();
+ if (flat != null) {
+ String[] allowed = flat.split(":");
+ for (String s : allowed) {
+ current.add(s);
+ }
+ }
+ return current;
+ }
+
+ private static String formatSettings(Collection<String> c) {
+ if (c == null || c.isEmpty()) {
+ return "";
+ }
+
+ StringBuilder b = new StringBuilder();
+ boolean start = true;
+ for (String s : c) {
+ if ("".equals(s)) {
+ continue;
+ }
+ if (!start) {
+ b.append(':');
+ }
+ b.append(s);
+ start = false;
+ }
+ return b.toString();
+ }
+
+
+
private void createAndConnectService(@NonNull ComponentName component, int userId) {
mCurrentVrService = VrManagerService.create(mContext, component, userId);
mCurrentVrService.connect();
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index 4848523..fb3c6ec 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -16,8 +16,8 @@
package com.android.server.wallpaper;
-import static android.app.WallpaperManager.FLAG_SET_SYSTEM;
-import static android.app.WallpaperManager.FLAG_SET_LOCK;
+import static android.app.WallpaperManager.FLAG_SYSTEM;
+import static android.app.WallpaperManager.FLAG_LOCK;
import static android.os.ParcelFileDescriptor.*;
import android.app.ActivityManager;
@@ -231,7 +231,7 @@
false, wallpaper, null);
}
if (lockWallpaperChanged
- || (wallpaper.whichPending & FLAG_SET_LOCK) != 0) {
+ || (wallpaper.whichPending & FLAG_LOCK) != 0) {
if (DEBUG) {
Slog.i(TAG, "Lock-relevant wallpaper changed");
}
@@ -505,7 +505,7 @@
&& mWallpaper.lastDiedTime + MIN_WALLPAPER_CRASH_TIME
> SystemClock.uptimeMillis()) {
Slog.w(TAG, "Reverting to built-in wallpaper!");
- clearWallpaperLocked(true, FLAG_SET_SYSTEM, mWallpaper.userId, null);
+ clearWallpaperLocked(true, FLAG_SYSTEM, mWallpaper.userId, null);
} else {
mWallpaper.lastDiedTime = SystemClock.uptimeMillis();
}
@@ -584,7 +584,7 @@
if (!bindWallpaperComponentLocked(comp, false, false,
wallpaper, null)) {
Slog.w(TAG, "Wallpaper no longer available; reverting to default");
- clearWallpaperLocked(false, FLAG_SET_SYSTEM, wallpaper.userId, null);
+ clearWallpaperLocked(false, FLAG_SYSTEM, wallpaper.userId, null);
}
}
}
@@ -664,7 +664,7 @@
if (doit) {
Slog.w(TAG, "Wallpaper uninstalled, removing: "
+ wallpaper.wallpaperComponent);
- clearWallpaperLocked(false, FLAG_SET_SYSTEM, wallpaper.userId, null);
+ clearWallpaperLocked(false, FLAG_SYSTEM, wallpaper.userId, null);
}
}
}
@@ -684,7 +684,7 @@
} catch (NameNotFoundException e) {
Slog.w(TAG, "Wallpaper component gone, removing: "
+ wallpaper.wallpaperComponent);
- clearWallpaperLocked(false, FLAG_SET_SYSTEM, wallpaper.userId, null);
+ clearWallpaperLocked(false, FLAG_SYSTEM, wallpaper.userId, null);
}
}
if (wallpaper.nextWallpaperComponent != null
@@ -746,7 +746,7 @@
if (DEBUG) {
Slog.i(TAG, "Unable to regenerate crop; resetting");
}
- clearWallpaperLocked(false, FLAG_SET_SYSTEM, UserHandle.USER_SYSTEM, null);
+ clearWallpaperLocked(false, FLAG_SYSTEM, UserHandle.USER_SYSTEM, null);
}
} else {
if (DEBUG) {
@@ -842,7 +842,7 @@
void switchUser(int userId, IRemoteCallback reply) {
synchronized (mLock) {
mCurrentUserId = userId;
- WallpaperData wallpaper = getWallpaperSafeLocked(userId, FLAG_SET_SYSTEM);
+ WallpaperData wallpaper = getWallpaperSafeLocked(userId, FLAG_SYSTEM);
// Not started watching yet, in case wallpaper data was loaded for other reasons.
if (wallpaper.wallpaperObserver == null) {
wallpaper.wallpaperObserver = new WallpaperObserver(wallpaper);
@@ -865,7 +865,7 @@
e = e1;
}
Slog.w(TAG, "Failure starting previous wallpaper", e);
- clearWallpaperLocked(false, FLAG_SET_SYSTEM, wallpaper.userId, reply);
+ clearWallpaperLocked(false, FLAG_SYSTEM, wallpaper.userId, reply);
}
}
@@ -885,12 +885,12 @@
}
void clearWallpaperLocked(boolean defaultFailed, int which, int userId, IRemoteCallback reply) {
- if (which != FLAG_SET_SYSTEM && which != FLAG_SET_LOCK) {
+ if (which != FLAG_SYSTEM && which != FLAG_LOCK) {
throw new IllegalArgumentException("Must specify exactly one kind of wallpaper to read");
}
WallpaperData wallpaper = null;
- if (which == FLAG_SET_LOCK) {
+ if (which == FLAG_LOCK) {
wallpaper = mLockWallpaperMap.get(userId);
if (wallpaper == null) {
// It's already gone; we're done.
@@ -916,7 +916,7 @@
if (wallpaper.wallpaperFile.exists()) {
wallpaper.wallpaperFile.delete();
wallpaper.cropFile.delete();
- if (which == FLAG_SET_LOCK) {
+ if (which == FLAG_LOCK) {
mLockWallpaperMap.remove(userId);
final IWallpaperManagerCallback cb = mKeyguardListener;
if (cb != null) {
@@ -1008,7 +1008,7 @@
}
synchronized (mLock) {
int userId = UserHandle.getCallingUserId();
- WallpaperData wallpaper = getWallpaperSafeLocked(userId, FLAG_SET_SYSTEM);
+ WallpaperData wallpaper = getWallpaperSafeLocked(userId, FLAG_SYSTEM);
if (width <= 0 || height <= 0) {
throw new IllegalArgumentException("width and height must be > 0");
}
@@ -1070,7 +1070,7 @@
}
synchronized (mLock) {
int userId = UserHandle.getCallingUserId();
- WallpaperData wallpaper = getWallpaperSafeLocked(userId, FLAG_SET_SYSTEM);
+ WallpaperData wallpaper = getWallpaperSafeLocked(userId, FLAG_SYSTEM);
if (padding.left < 0 || padding.top < 0 || padding.right < 0 || padding.bottom < 0) {
throw new IllegalArgumentException("padding must be positive: " + padding);
}
@@ -1103,13 +1103,13 @@
wallpaperUserId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
Binder.getCallingUid(), wallpaperUserId, false, true, "getWallpaper", null);
- if (which != FLAG_SET_SYSTEM && which != FLAG_SET_LOCK) {
+ if (which != FLAG_SYSTEM && which != FLAG_LOCK) {
throw new IllegalArgumentException("Must specify exactly one kind of wallpaper to read");
}
synchronized (mLock) {
final SparseArray<WallpaperData> whichSet =
- (which == FLAG_SET_LOCK) ? mLockWallpaperMap : mWallpaperMap;
+ (which == FLAG_LOCK) ? mLockWallpaperMap : mWallpaperMap;
WallpaperData wallpaper = whichSet.get(wallpaperUserId);
if (wallpaper == null) {
// common case, this is the first lookup post-boot of the system or
@@ -1157,12 +1157,12 @@
userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
Binder.getCallingUid(), userId, false, true, "getWallpaperIdForUser", null);
- if (which != FLAG_SET_SYSTEM && which != FLAG_SET_LOCK) {
+ if (which != FLAG_SYSTEM && which != FLAG_LOCK) {
throw new IllegalArgumentException("Must specify exactly one kind of wallpaper");
}
final SparseArray<WallpaperData> map =
- (which == FLAG_SET_LOCK) ? mLockWallpaperMap : mWallpaperMap;
+ (which == FLAG_LOCK) ? mLockWallpaperMap : mWallpaperMap;
synchronized (mLock) {
WallpaperData wallpaper = map.get(userId);
if (wallpaper != null) {
@@ -1186,7 +1186,7 @@
Rect cropHint, Bundle extras, int which, IWallpaperManagerCallback completion) {
checkPermission(android.Manifest.permission.SET_WALLPAPER);
- if ((which & (FLAG_SET_LOCK|FLAG_SET_SYSTEM)) == 0) {
+ if ((which & (FLAG_LOCK|FLAG_SYSTEM)) == 0) {
Slog.e(TAG, "Must specify a valid wallpaper category to set");
return null;
}
@@ -1285,6 +1285,7 @@
wallpaper.imageWallpaperPending = false;
if (bindWallpaperComponentLocked(name, false, true, wallpaper, null)) {
wallpaper.wallpaperId = makeWallpaperIdLocked();
+ notifyCallbacksLocked(wallpaper);
}
} finally {
Binder.restoreCallingIdentity(ident);
@@ -1637,7 +1638,7 @@
// Combined or just-system operations use the 'system' WallpaperData
// for this use; lock-only operations use the dedicated one.
final SparseArray<WallpaperData> whichSet =
- (which == FLAG_SET_LOCK) ? mLockWallpaperMap : mWallpaperMap;
+ (which == FLAG_LOCK) ? mLockWallpaperMap : mWallpaperMap;
WallpaperData wallpaper = whichSet.get(userId);
if (wallpaper == null) {
// common case, this is the first lookup post-boot of the system or
@@ -1648,7 +1649,7 @@
// yet a lock-only wallpaper set for this user, so we need to establish
// it now.
if (wallpaper == null) {
- if (which == FLAG_SET_LOCK) {
+ if (which == FLAG_LOCK) {
wallpaper = new WallpaperData(userId,
WALLPAPER_LOCK_ORIG, WALLPAPER_LOCK_CROP);
mLockWallpaperMap.put(userId, wallpaper);
diff --git a/services/core/java/com/android/server/webkit/WebViewUtilityImpl.java b/services/core/java/com/android/server/webkit/SystemImpl.java
similarity index 64%
rename from services/core/java/com/android/server/webkit/WebViewUtilityImpl.java
rename to services/core/java/com/android/server/webkit/SystemImpl.java
index 4dbd02d..6052a6e 100644
--- a/services/core/java/com/android/server/webkit/WebViewUtilityImpl.java
+++ b/services/core/java/com/android/server/webkit/SystemImpl.java
@@ -19,15 +19,22 @@
import android.app.ActivityManagerNative;
import android.app.AppGlobals;
import android.content.Context;
+import android.content.pm.IPackageDeleteObserver;
import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.UserInfo;
import android.content.res.XmlResourceParser;
+import android.os.Build;
import android.os.RemoteException;
import android.os.UserHandle;
+import android.os.UserManager;
+import android.provider.Settings.Global;
import android.provider.Settings;
import android.util.AndroidRuntimeException;
import android.util.Log;
-import android.webkit.WebViewFactory;
import android.webkit.WebViewFactory.MissingWebViewPackageException;
+import android.webkit.WebViewFactory;
import android.webkit.WebViewProviderInfo;
import com.android.internal.util.XmlUtils;
@@ -42,8 +49,8 @@
* Default implementation for the WebView preparation Utility interface.
* @hide
*/
-public class WebViewUtilityImpl implements WebViewUtilityInterface {
- private static final String TAG = WebViewUtilityImpl.class.getSimpleName();
+public class SystemImpl implements SystemInterface {
+ private static final String TAG = SystemImpl.class.getSimpleName();
private static final String TAG_START = "webviewproviders";
private static final String TAG_WEBVIEW_PROVIDER = "webviewprovider";
private static final String TAG_PACKAGE_NAME = "packageName";
@@ -87,10 +94,10 @@
parser.getAttributeValue(null, TAG_AVAILABILITY));
boolean isFallback = "true".equals(
parser.getAttributeValue(null, TAG_FALLBACK));
- WebViewProviderInfo currentProvider =
- new WebViewProviderInfo(packageName, description, availableByDefault,
- isFallback, readSignatures(parser));
- if (currentProvider.isFallbackPackage()) {
+ WebViewProviderInfo currentProvider = new WebViewProviderInfo(
+ packageName, description, availableByDefault, isFallback,
+ readSignatures(parser));
+ if (currentProvider.isFallback) {
numFallbackPackages++;
if (numFallbackPackages > 1) {
throw new AndroidRuntimeException(
@@ -158,4 +165,67 @@
} catch (RemoteException e) {
}
}
+
+ @Override
+ public boolean isFallbackLogicEnabled() {
+ // Note that this is enabled by default (i.e. if the setting hasn't been set).
+ return Settings.Global.getInt(AppGlobals.getInitialApplication().getContentResolver(),
+ Settings.Global.WEBVIEW_FALLBACK_LOGIC_ENABLED, 1) == 1;
+ }
+
+ @Override
+ public void enableFallbackLogic(boolean enable) {
+ Settings.Global.putInt(AppGlobals.getInitialApplication().getContentResolver(),
+ Settings.Global.WEBVIEW_FALLBACK_LOGIC_ENABLED, enable ? 1 : 0);
+ }
+
+ @Override
+ public void uninstallAndDisablePackageForAllUsers(Context context, String packageName) {
+ context.getPackageManager().deletePackage(packageName,
+ new IPackageDeleteObserver.Stub() {
+ public void packageDeleted(String packageName, int returnCode) {
+ // Ignore returnCode since the deletion could fail, e.g. we might be trying
+ // to delete a non-updated system-package (and we should still disable the
+ // package)
+ enablePackageForAllUsers(context, packageName, false);
+ }
+ }, PackageManager.DELETE_SYSTEM_APP | PackageManager.DELETE_ALL_USERS);
+ }
+
+ @Override
+ public void enablePackageForAllUsers(Context context, String packageName, boolean enable) {
+ UserManager userManager = (UserManager)context.getSystemService(Context.USER_SERVICE);
+ for(UserInfo userInfo : userManager.getUsers()) {
+ enablePackageForUser(packageName, enable, userInfo.id);
+ }
+ }
+
+ @Override
+ public void enablePackageForUser(String packageName, boolean enable, int userId) {
+ try {
+ AppGlobals.getPackageManager().setApplicationEnabledSetting(
+ packageName,
+ enable ? PackageManager.COMPONENT_ENABLED_STATE_DEFAULT :
+ PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER, 0,
+ userId, null);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Tried to disable " + packageName + " for user " + userId + ": " + e);
+ }
+ }
+
+ @Override
+ public boolean systemIsDebuggable() {
+ return Build.IS_DEBUGGABLE;
+ }
+
+ @Override
+ public PackageInfo getPackageInfoForProvider(WebViewProviderInfo configInfo)
+ throws NameNotFoundException {
+ PackageManager pm = AppGlobals.getInitialApplication().getPackageManager();
+ return pm.getPackageInfo(configInfo.packageName, PACKAGE_FLAGS);
+ }
+
+ // flags declaring we want extra info from the package manager for webview providers
+ private final static int PACKAGE_FLAGS = PackageManager.GET_META_DATA
+ | PackageManager.GET_SIGNATURES | PackageManager.MATCH_DEBUG_TRIAGED_MISSING;
}
diff --git a/services/core/java/com/android/server/webkit/WebViewUtilityInterface.java b/services/core/java/com/android/server/webkit/SystemInterface.java
similarity index 67%
rename from services/core/java/com/android/server/webkit/WebViewUtilityInterface.java
rename to services/core/java/com/android/server/webkit/SystemInterface.java
index 1919f40..b5eb0a7 100644
--- a/services/core/java/com/android/server/webkit/WebViewUtilityInterface.java
+++ b/services/core/java/com/android/server/webkit/SystemInterface.java
@@ -16,22 +16,35 @@
package com.android.server.webkit;
-import android.webkit.WebViewProviderInfo;
import android.content.Context;
import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.webkit.WebViewProviderInfo;
/**
- * Utility interface for the WebViewUpdateService.
+ * System interface for the WebViewUpdateService.
* This interface provides a way to test the WebView preparation mechanism - during normal use this
* interface is implemented using calls to the Android framework, but by providing an alternative
* implementation we can test the WebView preparation logic without reaching other framework code.
+ *
* @hide
*/
-public interface WebViewUtilityInterface {
+public interface SystemInterface {
public WebViewProviderInfo[] getWebViewPackages();
public int onWebViewProviderChanged(PackageInfo packageInfo);
public String getUserChosenWebViewProvider(Context context);
public void updateUserSetting(Context context, String newProviderName);
public void killPackageDependents(String packageName);
+
+ public boolean isFallbackLogicEnabled();
+ public void enableFallbackLogic(boolean enable);
+
+ public void uninstallAndDisablePackageForAllUsers(Context context, String packageName);
+ public void enablePackageForAllUsers(Context context, String packageName, boolean enable);
+ public void enablePackageForUser(String packageName, boolean enable, int userId);
+
+ public boolean systemIsDebuggable();
+ public PackageInfo getPackageInfoForProvider(WebViewProviderInfo configInfo)
+ throws NameNotFoundException;
}
diff --git a/services/core/java/com/android/server/webkit/WebViewUpdateService.java b/services/core/java/com/android/server/webkit/WebViewUpdateService.java
index 50699f8..4669676 100644
--- a/services/core/java/com/android/server/webkit/WebViewUpdateService.java
+++ b/services/core/java/com/android/server/webkit/WebViewUpdateService.java
@@ -16,28 +16,20 @@
package com.android.server.webkit;
-import android.app.ActivityManagerNative;
-import android.app.AppGlobals;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.IPackageDeleteObserver;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.Signature;
-import android.content.pm.UserInfo;
import android.os.Binder;
import android.os.PatternMatcher;
import android.os.Process;
-import android.os.RemoteException;
import android.os.ResultReceiver;
import android.os.UserHandle;
-import android.os.UserManager;
-import android.provider.Settings.Global;
-import android.provider.Settings;
-import android.util.AndroidRuntimeException;
+import android.util.Base64;
import android.util.Slog;
import android.webkit.IWebViewUpdateService;
import android.webkit.WebViewFactory;
@@ -49,7 +41,6 @@
import java.io.FileDescriptor;
import java.util.ArrayList;
import java.util.Arrays;
-import java.util.Iterator;
import java.util.List;
/**
@@ -72,15 +63,13 @@
// The WebView package currently in use (or the one we are preparing).
private PackageInfo mCurrentWebViewPackage = null;
- // The WebView providers that are currently available.
- private WebViewProviderInfo[] mCurrentValidWebViewPackages = null;
private BroadcastReceiver mWebViewUpdatedReceiver;
- private WebViewUtilityInterface mWebViewUtility;
+ private SystemInterface mSystemInterface;
public WebViewUpdateService(Context context) {
super(context);
- mWebViewUtility = new WebViewUtilityImpl();
+ mSystemInterface = new SystemImpl();
}
@Override
@@ -102,7 +91,7 @@
// Ensure that we only heed PACKAGE_CHANGED intents if they change an entire
// package, not just a component
if (intent.getAction().equals(Intent.ACTION_PACKAGE_CHANGED)) {
- if (!WebViewFactory.entirePackageChanged(intent)) {
+ if (!entirePackageChanged(intent)) {
return;
}
}
@@ -116,7 +105,7 @@
updateFallbackState(context, intent);
- for (WebViewProviderInfo provider : mWebViewUtility.getWebViewPackages()) {
+ for (WebViewProviderInfo provider : mSystemInterface.getWebViewPackages()) {
String webviewPackage = "package:" + provider.packageName;
if (webviewPackage.equals(intent.getDataString())) {
@@ -126,7 +115,6 @@
PackageInfo newPackage = null;
synchronized(WebViewUpdateService.this) {
try {
- updateValidWebViewPackages();
newPackage = findPreferredWebViewPackage();
if (mCurrentWebViewPackage != null)
oldProviderName = mCurrentWebViewPackage.packageName;
@@ -155,7 +143,7 @@
// package that was not the previous provider then we must kill
// packages dependent on the old package ourselves. The framework
// only kills dependents of packages that are being removed.
- mWebViewUtility.killPackageDependents(oldProviderName);
+ mSystemInterface.killPackageDependents(oldProviderName);
}
return;
}
@@ -168,7 +156,7 @@
filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
filter.addDataScheme("package");
// Make sure we only receive intents for WebView packages from our config file.
- for (WebViewProviderInfo provider : mWebViewUtility.getWebViewPackages()) {
+ for (WebViewProviderInfo provider : mSystemInterface.getWebViewPackages()) {
filter.addDataSchemeSpecificPart(provider.packageName, PatternMatcher.PATTERN_LITERAL);
}
getContext().registerReceiver(mWebViewUpdatedReceiver, filter);
@@ -180,42 +168,34 @@
publishBinderService("webviewupdate", new BinderService(), true /*allowIsolated*/);
}
- private static boolean existsValidNonFallbackProvider(WebViewProviderInfo[] providers) {
+ private boolean existsValidNonFallbackProvider(WebViewProviderInfo[] providers) {
for (WebViewProviderInfo provider : providers) {
- if (provider.isAvailableByDefault() && provider.isEnabled()
- && provider.isValidProvider() && !provider.isFallbackPackage()) {
- return true;
+ if (provider.availableByDefault && !provider.isFallback) {
+ try {
+ PackageInfo packageInfo = mSystemInterface.getPackageInfoForProvider(provider);
+ if (isEnabledPackage(packageInfo) && isValidProvider(provider, packageInfo)) {
+ return true;
+ }
+ } catch (NameNotFoundException e) {
+ // A non-existent provider is neither valid nor enabled
+ }
}
}
return false;
}
- private static void enablePackageForUser(String packageName, boolean enable, int userId) {
- try {
- AppGlobals.getPackageManager().setApplicationEnabledSetting(
- packageName,
- enable ? PackageManager.COMPONENT_ENABLED_STATE_DEFAULT :
- PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER, 0,
- userId, null);
- } catch (RemoteException e) {
- Slog.w(TAG, "Tried to disable " + packageName + " for user " + userId + ": " + e);
- }
- }
-
/**
* Called when a new user has been added to update the state of its fallback package.
*/
void handleNewUser(int userId) {
- if (!isFallbackLogicEnabled()) return;
+ if (!mSystemInterface.isFallbackLogicEnabled()) return;
- WebViewProviderInfo[] webviewProviders = mWebViewUtility.getWebViewPackages();
+ WebViewProviderInfo[] webviewProviders = mSystemInterface.getWebViewPackages();
WebViewProviderInfo fallbackProvider = getFallbackProvider(webviewProviders);
if (fallbackProvider == null) return;
- boolean existsValidNonFallbackProvider =
- existsValidNonFallbackProvider(webviewProviders);
- enablePackageForUser(fallbackProvider.packageName, !existsValidNonFallbackProvider,
- userId);
+ mSystemInterface.enablePackageForUser(fallbackProvider.packageName,
+ !existsValidNonFallbackProvider(webviewProviders), userId);
}
/**
@@ -224,9 +204,9 @@
* otherwise, enable the fallback package.
*/
void updateFallbackState(final Context context, final Intent intent) {
- if (!isFallbackLogicEnabled()) return;
+ if (!mSystemInterface.isFallbackLogicEnabled()) return;
- WebViewProviderInfo[] webviewProviders = mWebViewUtility.getWebViewPackages();
+ WebViewProviderInfo[] webviewProviders = mSystemInterface.getWebViewPackages();
if (intent != null && (intent.getAction().equals(Intent.ACTION_PACKAGE_ADDED)
|| intent.getAction().equals(Intent.ACTION_PACKAGE_CHANGED))) {
@@ -236,7 +216,7 @@
for (WebViewProviderInfo provider : webviewProviders) {
String webviewPackage = "package:" + provider.packageName;
if (webviewPackage.equals(intent.getDataString())) {
- if (provider.isAvailableByDefault()) {
+ if (provider.availableByDefault) {
changedPackage = provider.packageName;
}
break;
@@ -251,76 +231,44 @@
if (fallbackProvider == null) return;
boolean existsValidNonFallbackProvider = existsValidNonFallbackProvider(webviewProviders);
+ boolean isFallbackEnabled = false;
+ try {
+ isFallbackEnabled =
+ isEnabledPackage(mSystemInterface.getPackageInfoForProvider(fallbackProvider));
+ } catch (NameNotFoundException e) {
+ }
+
if (existsValidNonFallbackProvider
// During an OTA the primary user's WebView state might differ from other users', so
// ignore the state of that user during boot.
- && (fallbackProvider.isEnabled() || intent == null)) {
- // Uninstall and disable fallback package for all users.
- context.getPackageManager().deletePackage(fallbackProvider.packageName,
- new IPackageDeleteObserver.Stub() {
- public void packageDeleted(String packageName, int returnCode) {
- // Ignore returnCode since the deletion could fail, e.g. we might be trying
- // to delete a non-updated system-package (and we should still disable the
- // package)
- UserManager userManager =
- (UserManager)context.getSystemService(Context.USER_SERVICE);
- // Disable the fallback package for all users.
- for(UserInfo userInfo : userManager.getUsers()) {
- enablePackageForUser(packageName, false, userInfo.id);
- }
- }
- }, PackageManager.DELETE_SYSTEM_APP | PackageManager.DELETE_ALL_USERS);
+ && (isFallbackEnabled || intent == null)) {
+ mSystemInterface.uninstallAndDisablePackageForAllUsers(context,
+ fallbackProvider.packageName);
} else if (!existsValidNonFallbackProvider
// During an OTA the primary user's WebView state might differ from other users', so
// ignore the state of that user during boot.
- && (!fallbackProvider.isEnabled() || intent==null)) {
+ && (!isFallbackEnabled || intent==null)) {
// Enable the fallback package for all users.
- UserManager userManager =
- (UserManager)context.getSystemService(Context.USER_SERVICE);
- for(UserInfo userInfo : userManager.getUsers()) {
- enablePackageForUser(fallbackProvider.packageName, true, userInfo.id);
- }
+ mSystemInterface.enablePackageForAllUsers(context, fallbackProvider.packageName, true);
}
}
- private static boolean isFallbackLogicEnabled() {
- // Note that this is enabled by default (i.e. if the setting hasn't been set).
- return Settings.Global.getInt(AppGlobals.getInitialApplication().getContentResolver(),
- Settings.Global.WEBVIEW_FALLBACK_LOGIC_ENABLED, 1) == 1;
- }
-
- private static void enableFallbackLogic(boolean enable) {
- Settings.Global.putInt(AppGlobals.getInitialApplication().getContentResolver(),
- Settings.Global.WEBVIEW_FALLBACK_LOGIC_ENABLED, enable ? 1 : 0);
- }
-
/**
* Returns the only fallback provider, or null if there is none.
*/
private static WebViewProviderInfo getFallbackProvider(WebViewProviderInfo[] webviewPackages) {
for (WebViewProviderInfo provider : webviewPackages) {
- if (provider.isFallbackPackage()) {
+ if (provider.isFallback) {
return provider;
}
}
return null;
}
- private static boolean containsAvailableNonFallbackProvider(
- WebViewProviderInfo[] webviewPackages) {
- for (WebViewProviderInfo provider : webviewPackages) {
- if (provider.isAvailableByDefault() && provider.isEnabled()
- && provider.isValidProvider() && !provider.isFallbackPackage()) {
- return true;
- }
- }
- return false;
- }
-
private boolean isFallbackPackage(String packageName) {
- if (packageName == null || !isFallbackLogicEnabled()) return false;
+ if (packageName == null || !mSystemInterface.isFallbackLogicEnabled()) return false;
- WebViewProviderInfo[] webviewPackages = mWebViewUtility.getWebViewPackages();
+ WebViewProviderInfo[] webviewPackages = mSystemInterface.getWebViewPackages();
WebViewProviderInfo fallbackProvider = getFallbackProvider(webviewPackages);
return (fallbackProvider != null
&& packageName.equals(fallbackProvider.packageName));
@@ -336,7 +284,6 @@
updateFallbackState(getContext(), null);
try {
synchronized(this) {
- updateValidWebViewPackages();
mCurrentWebViewPackage = findPreferredWebViewPackage();
onWebViewProviderChanged(mCurrentWebViewPackage);
}
@@ -357,13 +304,13 @@
PackageInfo newPackage = null;
synchronized(this) {
oldPackage = mCurrentWebViewPackage;
- mWebViewUtility.updateUserSetting(getContext(), newProviderName);
+ mSystemInterface.updateUserSetting(getContext(), newProviderName);
try {
newPackage = findPreferredWebViewPackage();
if (oldPackage != null && newPackage.packageName.equals(oldPackage.packageName)) {
// If we don't perform the user change, revert the settings change.
- mWebViewUtility.updateUserSetting(getContext(), newPackage.packageName);
+ mSystemInterface.updateUserSetting(getContext(), newPackage.packageName);
return newPackage.packageName;
}
} catch (WebViewFactory.MissingWebViewPackageException e) {
@@ -377,7 +324,7 @@
}
// Kill apps using the old provider
if (oldPackage != null) {
- mWebViewUtility.killPackageDependents(oldPackage.packageName);
+ mSystemInterface.killPackageDependents(oldPackage.packageName);
}
return newPackage.packageName;
}
@@ -391,14 +338,14 @@
mAnyWebViewInstalled = true;
if (mNumRelroCreationsStarted == mNumRelroCreationsFinished) {
mCurrentWebViewPackage = newPackage;
- mWebViewUtility.updateUserSetting(getContext(), newPackage.packageName);
+ mSystemInterface.updateUserSetting(getContext(), newPackage.packageName);
// The relro creations might 'finish' (not start at all) before
// WebViewFactory.onWebViewProviderChanged which means we might not know the number
// of started creations before they finish.
mNumRelroCreationsStarted = NUMBER_OF_RELROS_UNKNOWN;
mNumRelroCreationsFinished = 0;
- mNumRelroCreationsStarted = mWebViewUtility.onWebViewProviderChanged(newPackage);
+ mNumRelroCreationsStarted = mSystemInterface.onWebViewProviderChanged(newPackage);
// If the relro creations finish before we know the number of started creations we
// will have to do any cleanup/notifying here.
checkIfRelrosDoneLocked();
@@ -408,24 +355,42 @@
}
}
- /**
- * Updates the currently valid WebView provider packages.
- * Should be used when a provider has been installed or removed.
- * @hide
- * */
- private void updateValidWebViewPackages() {
- List<WebViewProviderInfo> webViewProviders =
- new ArrayList<WebViewProviderInfo>(Arrays.asList(mWebViewUtility.getWebViewPackages()));
- Iterator<WebViewProviderInfo> it = webViewProviders.iterator();
- // remove non-valid packages
- while(it.hasNext()) {
- WebViewProviderInfo current = it.next();
- if (!current.isValidProvider())
- it.remove();
+ private ProviderAndPackageInfo[] getValidWebViewPackagesAndInfos() {
+ WebViewProviderInfo[] allProviders = mSystemInterface.getWebViewPackages();
+ List<ProviderAndPackageInfo> providers = new ArrayList<>();
+ for(int n = 0; n < allProviders.length; n++) {
+ try {
+ PackageInfo packageInfo =
+ mSystemInterface.getPackageInfoForProvider(allProviders[n]);
+ if (isValidProvider(allProviders[n], packageInfo)) {
+ providers.add(new ProviderAndPackageInfo(allProviders[n], packageInfo));
+ }
+ } catch (NameNotFoundException e) {
+ // Don't add non-existent packages
+ }
}
- synchronized(this) {
- mCurrentValidWebViewPackages =
- webViewProviders.toArray(new WebViewProviderInfo[webViewProviders.size()]);
+ return providers.toArray(new ProviderAndPackageInfo[providers.size()]);
+ }
+
+ /**
+ * Fetch only the currently valid WebView packages.
+ **/
+ private WebViewProviderInfo[] getValidWebViewPackages() {
+ ProviderAndPackageInfo[] providersAndPackageInfos = getValidWebViewPackagesAndInfos();
+ WebViewProviderInfo[] providers = new WebViewProviderInfo[providersAndPackageInfos.length];
+ for(int n = 0; n < providersAndPackageInfos.length; n++) {
+ providers[n] = providersAndPackageInfos[n].provider;
+ }
+ return providers;
+ }
+
+ private class ProviderAndPackageInfo {
+ public final WebViewProviderInfo provider;
+ public final PackageInfo packageInfo;
+
+ public ProviderAndPackageInfo(WebViewProviderInfo provider, PackageInfo packageInfo) {
+ this.provider = provider;
+ this.packageInfo = packageInfo;
}
}
@@ -437,28 +402,30 @@
* @hide
*/
private PackageInfo findPreferredWebViewPackage() {
- WebViewProviderInfo[] providers = mCurrentValidWebViewPackages;
+ ProviderAndPackageInfo[] providers = getValidWebViewPackagesAndInfos();
- String userChosenProvider = mWebViewUtility.getUserChosenWebViewProvider(getContext());
+ String userChosenProvider = mSystemInterface.getUserChosenWebViewProvider(getContext());
// If the user has chosen provider, use that
- for (WebViewProviderInfo provider : providers) {
- if (provider.packageName.equals(userChosenProvider) && provider.isEnabled()) {
- return provider.getPackageInfo();
+ for (ProviderAndPackageInfo providerAndPackage : providers) {
+ if (providerAndPackage.provider.packageName.equals(userChosenProvider)
+ && isEnabledPackage(providerAndPackage.packageInfo)) {
+ return providerAndPackage.packageInfo;
}
}
// User did not choose, or the choice failed; use the most stable provider that is
// enabled and available by default (not through user choice).
- for (WebViewProviderInfo provider : providers) {
- if (provider.isAvailableByDefault() && provider.isEnabled()) {
- return provider.getPackageInfo();
+ for (ProviderAndPackageInfo providerAndPackage : providers) {
+ if (providerAndPackage.provider.availableByDefault
+ && isEnabledPackage(providerAndPackage.packageInfo)) {
+ return providerAndPackage.packageInfo;
}
}
// Could not find any enabled package either, use the most stable provider.
- for (WebViewProviderInfo provider : providers) {
- return provider.getPackageInfo();
+ for (ProviderAndPackageInfo providerAndPackage : providers) {
+ return providerAndPackage.packageInfo;
}
mAnyWebViewInstalled = false;
@@ -466,6 +433,64 @@
"Could not find a loadable WebView package");
}
+
+ /**
+ * Returns whether this provider is valid for use as a WebView provider.
+ */
+ public boolean isValidProvider(WebViewProviderInfo configInfo,
+ PackageInfo packageInfo) {
+ if (providerHasValidSignature(configInfo, packageInfo) &&
+ WebViewFactory.getWebViewLibrary(packageInfo.applicationInfo) != null) {
+ return true;
+ }
+ return false;
+ }
+
+ private boolean providerHasValidSignature(WebViewProviderInfo provider,
+ PackageInfo packageInfo) {
+ if (mSystemInterface.systemIsDebuggable()) {
+ return true;
+ }
+ Signature[] packageSignatures;
+ // If no signature is declared, instead check whether the package is included in the
+ // system.
+ if (provider.signatures == null || provider.signatures.length == 0) {
+ return packageInfo.applicationInfo.isSystemApp();
+ }
+ packageSignatures = packageInfo.signatures;
+ if (packageSignatures.length != 1)
+ return false;
+
+ final byte[] packageSignature = packageSignatures[0].toByteArray();
+ // Return whether the package signature matches any of the valid signatures
+ for (String signature : provider.signatures) {
+ final byte[] validSignature = Base64.decode(signature, Base64.DEFAULT);
+ if (Arrays.equals(packageSignature, validSignature))
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Returns whether the given package is enabled.
+ * This state can be changed by the user from Settings->Apps
+ */
+ public boolean isEnabledPackage(PackageInfo packageInfo) {
+ return packageInfo.applicationInfo.enabled;
+ }
+
+ /**
+ * Returns whether the entire package from an ACTION_PACKAGE_CHANGED intent was changed (rather
+ * than just one of its components).
+ * @hide
+ */
+ public static boolean entirePackageChanged(Intent intent) {
+ String[] componentList =
+ intent.getStringArrayExtra(Intent.EXTRA_CHANGED_COMPONENT_NAME_LIST);
+ return Arrays.asList(componentList).contains(
+ intent.getDataString().substring("package:".length()));
+ }
+
/**
* Returns whether WebView is ready and is not going to go through its preparation phase again
* directly.
@@ -588,19 +613,22 @@
throw new SecurityException(msg);
}
- return WebViewUpdateService.this.changeProviderAndSetting(newProvider);
- }
-
- @Override // Binder call
- public WebViewProviderInfo[] getValidWebViewPackages() {
- synchronized(WebViewUpdateService.this) {
- return mCurrentValidWebViewPackages;
+ long callingId = Binder.clearCallingIdentity();
+ try {
+ return WebViewUpdateService.this.changeProviderAndSetting(newProvider);
+ } finally {
+ Binder.restoreCallingIdentity(callingId);
}
}
@Override // Binder call
+ public WebViewProviderInfo[] getValidWebViewPackages() {
+ return WebViewUpdateService.this.getValidWebViewPackages();
+ }
+
+ @Override // Binder call
public WebViewProviderInfo[] getAllWebViewPackages() {
- return WebViewUpdateService.this.mWebViewUtility.getWebViewPackages();
+ return WebViewUpdateService.this.mSystemInterface.getWebViewPackages();
}
@Override // Binder call
@@ -630,7 +658,7 @@
throw new SecurityException(msg);
}
- WebViewUpdateService.enableFallbackLogic(enable);
+ WebViewUpdateService.this.mSystemInterface.enableFallbackLogic(enable);
}
}
}
diff --git a/services/core/java/com/android/server/webkit/WebViewUpdateServiceShellCommand.java b/services/core/java/com/android/server/webkit/WebViewUpdateServiceShellCommand.java
index a9461e8..68448f3 100644
--- a/services/core/java/com/android/server/webkit/WebViewUpdateServiceShellCommand.java
+++ b/services/core/java/com/android/server/webkit/WebViewUpdateServiceShellCommand.java
@@ -36,12 +36,13 @@
final PrintWriter pw = getOutPrintWriter();
try {
- // TODO(gsennton) add command for changing WebView provider
switch(cmd) {
case "enable-redundant-packages":
return enableFallbackLogic(false);
case "disable-redundant-packages":
return enableFallbackLogic(true);
+ case "set-webview-implementation":
+ return setWebViewImplementation();
default:
return handleDefaultCommands(cmd);
}
@@ -58,6 +59,21 @@
return 0;
}
+ private int setWebViewImplementation() throws RemoteException {
+ final PrintWriter pw = getOutPrintWriter();
+ String shellChosenPackage = getNextArg();
+ String newPackage = mInterface.changeProviderAndSetting(shellChosenPackage);
+ if (shellChosenPackage.equals(newPackage)) {
+ pw.println("Success");
+ return 0;
+ } else {
+ pw.println(String.format(
+ "Failed to switch to %s, the WebView implementation is now provided by %s.",
+ shellChosenPackage, newPackage));
+ return 1;
+ }
+ }
+
@Override
public void onHelp() {
PrintWriter pw = getOutPrintWriter();
@@ -72,6 +88,8 @@
pw.println(" disable-redundant-packages");
pw.println(" Disallow installing and enabling fallback packages when a more-preferred");
pw.println(" package is available.");
+ pw.println(" set-webview-implementation PACKAGE");
+ pw.println(" Set the WebView implementation to the specified package.");
pw.println();
}
}
diff --git a/services/core/java/com/android/server/wm/AccessibilityController.java b/services/core/java/com/android/server/wm/AccessibilityController.java
index 2c15818..bae628a 100644
--- a/services/core/java/com/android/server/wm/AccessibilityController.java
+++ b/services/core/java/com/android/server/wm/AccessibilityController.java
@@ -21,6 +21,7 @@
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
+import android.annotation.NonNull;
import android.app.Service;
import android.content.Context;
import android.graphics.Canvas;
@@ -38,6 +39,7 @@
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
+import android.text.TextUtils;
import android.util.ArraySet;
import android.util.Log;
import android.util.Slog;
@@ -122,6 +124,12 @@
}
}
+ public void getMagnificationRegionsLocked(Region outMagnified, Region outAvailable) {
+ if (mDisplayMagnifier != null) {
+ mDisplayMagnifier.getMagnificationRegionsLocked(outMagnified, outAvailable);
+ }
+ }
+
public void onRectangleOnScreenRequestedLocked(Rect rectangle) {
if (mDisplayMagnifier != null) {
mDisplayMagnifier.onRectangleOnScreenRequestedLocked(rectangle);
@@ -392,6 +400,10 @@
return spec;
}
+ public void getMagnificationRegionsLocked(Region outMagnified, Region outAvailable) {
+ mMagnifedViewport.getBoundsLocked(outMagnified, outAvailable);
+ }
+
public void destroyLocked() {
mMagnifedViewport.destroyWindow();
}
@@ -413,6 +425,7 @@
private final Matrix mTempMatrix = new Matrix();
private final Region mMagnifiedBounds = new Region();
+ private final Region mAvailableBounds = new Region();
private final Region mOldMagnifiedBounds = new Region();
private final Region mOldAvailableBounds = new Region();
@@ -450,6 +463,12 @@
recomputeBoundsLocked();
}
+ public void getBoundsLocked(@NonNull Region outMagnified,
+ @NonNull Region outAvailable) {
+ outMagnified.set(mMagnifiedBounds);
+ outAvailable.set(mAvailableBounds);
+ }
+
public void updateMagnificationSpecLocked(MagnificationSpec spec) {
if (spec != null) {
mMagnificationSpec.initialize(spec.scale, spec.offsetX, spec.offsetY);
@@ -469,14 +488,11 @@
final int screenWidth = mTempPoint.x;
final int screenHeight = mTempPoint.y;
- Region magnifiedBounds = mMagnifiedBounds;
- magnifiedBounds.set(0, 0, 0, 0);
-
- Region availableBounds = mTempRegion1;
- availableBounds.set(0, 0, screenWidth, screenHeight);
+ mMagnifiedBounds.set(0, 0, 0, 0);
+ mAvailableBounds.set(0, 0, screenWidth, screenHeight);
if (mCircularPath != null) {
- availableBounds.setPath(mCircularPath, availableBounds);
+ mAvailableBounds.setPath(mCircularPath, mAvailableBounds);
}
Region nonMagnifiedBounds = mTempRegion4;
@@ -494,36 +510,37 @@
continue;
}
- Region windowBounds = mTempRegion2;
+ // Consider the touchable portion of the window
Matrix matrix = mTempMatrix;
populateTransformationMatrixLocked(windowState, matrix);
+ Region touchableRegion = mTempRegion3;
+ windowState.getTouchableRegion(touchableRegion);
+ Rect touchableFrame = mTempRect1;
+ touchableRegion.getBounds(touchableFrame);
RectF windowFrame = mTempRectF;
+ windowFrame.set(touchableFrame);
+ windowFrame.offset(-windowState.mFrame.left, -windowState.mFrame.top);
+ matrix.mapRect(windowFrame);
+ Region windowBounds = mTempRegion2;
+ windowBounds.set((int) windowFrame.left, (int) windowFrame.top,
+ (int) windowFrame.right, (int) windowFrame.bottom);
+ // Only update new regions
+ Region portionOfWindowAlreadyAccountedFor = mTempRegion3;
+ portionOfWindowAlreadyAccountedFor.set(mMagnifiedBounds);
+ portionOfWindowAlreadyAccountedFor.op(nonMagnifiedBounds, Region.Op.UNION);
+ windowBounds.op(portionOfWindowAlreadyAccountedFor, Region.Op.DIFFERENCE);
if (mWindowManagerService.mPolicy.canMagnifyWindow(windowState.mAttrs.type)) {
- windowFrame.set(windowState.mFrame);
- windowFrame.offset(-windowFrame.left, -windowFrame.top);
- matrix.mapRect(windowFrame);
- windowBounds.set((int) windowFrame.left, (int) windowFrame.top,
- (int) windowFrame.right, (int) windowFrame.bottom);
- magnifiedBounds.op(windowBounds, Region.Op.UNION);
- magnifiedBounds.op(availableBounds, Region.Op.INTERSECT);
+ mMagnifiedBounds.op(windowBounds, Region.Op.UNION);
+ mMagnifiedBounds.op(mAvailableBounds, Region.Op.INTERSECT);
} else {
- Region touchableRegion = mTempRegion3;
- windowState.getTouchableRegion(touchableRegion);
- Rect touchableFrame = mTempRect1;
- touchableRegion.getBounds(touchableFrame);
- windowFrame.set(touchableFrame);
- windowFrame.offset(-windowState.mFrame.left, -windowState.mFrame.top);
- matrix.mapRect(windowFrame);
- windowBounds.set((int) windowFrame.left, (int) windowFrame.top,
- (int) windowFrame.right, (int) windowFrame.bottom);
nonMagnifiedBounds.op(windowBounds, Region.Op.UNION);
- windowBounds.op(magnifiedBounds, Region.Op.DIFFERENCE);
- availableBounds.op(windowBounds, Region.Op.DIFFERENCE);
+ mAvailableBounds.op(windowBounds, Region.Op.DIFFERENCE);
}
+ // Update accounted bounds
Region accountedBounds = mTempRegion2;
- accountedBounds.set(magnifiedBounds);
+ accountedBounds.set(mMagnifiedBounds);
accountedBounds.op(nonMagnifiedBounds, Region.Op.UNION);
accountedBounds.op(0, 0, screenWidth, screenHeight, Region.Op.INTERSECT);
@@ -539,15 +556,15 @@
visibleWindows.clear();
- magnifiedBounds.op(mDrawBorderInset, mDrawBorderInset,
+ mMagnifiedBounds.op(mDrawBorderInset, mDrawBorderInset,
screenWidth - mDrawBorderInset, screenHeight - mDrawBorderInset,
Region.Op.INTERSECT);
- final boolean magnifiedChanged = !mOldMagnifiedBounds.equals(magnifiedBounds);
- final boolean availableChanged = !mOldAvailableBounds.equals(availableBounds);
+ final boolean magnifiedChanged = !mOldMagnifiedBounds.equals(mMagnifiedBounds);
+ final boolean availableChanged = !mOldAvailableBounds.equals(mAvailableBounds);
if (magnifiedChanged || availableChanged) {
if (magnifiedChanged) {
- mWindow.setBounds(magnifiedBounds);
+ mWindow.setBounds(mMagnifiedBounds);
Rect dirtyRect = mTempRect1;
if (mFullRedrawNeeded) {
mFullRedrawNeeded = false;
@@ -557,23 +574,23 @@
mWindow.invalidate(dirtyRect);
} else {
Region dirtyRegion = mTempRegion3;
- dirtyRegion.set(magnifiedBounds);
+ dirtyRegion.set(mMagnifiedBounds);
dirtyRegion.op(mOldMagnifiedBounds, Region.Op.UNION);
dirtyRegion.op(nonMagnifiedBounds, Region.Op.INTERSECT);
dirtyRegion.getBounds(dirtyRect);
mWindow.invalidate(dirtyRect);
}
- mOldMagnifiedBounds.set(magnifiedBounds);
+ mOldMagnifiedBounds.set(mMagnifiedBounds);
}
if (availableChanged) {
- mOldAvailableBounds.set(availableBounds);
+ mOldAvailableBounds.set(mAvailableBounds);
}
final SomeArgs args = SomeArgs.obtain();
- args.arg1 = Region.obtain(magnifiedBounds);
- args.arg2 = Region.obtain(availableBounds);
+ args.arg1 = Region.obtain(mMagnifiedBounds);
+ args.arg2 = Region.obtain(mAvailableBounds);
mHandler.obtainMessage(
MyHandler.MESSAGE_NOTIFY_MAGNIFIED_BOUNDS_CHANGED, args).sendToTarget();
}
@@ -1197,6 +1214,8 @@
window.type = windowState.mAttrs.type;
window.layer = windowState.mLayer;
window.token = windowState.mClient.asBinder();
+ window.title = windowState.mAttrs.getTitle();
+ window.accessibilityIdOfAnchor = windowState.mAttrs.accessibilityIdOfAnchor;
WindowState attachedWindow = windowState.mAttachedWindow;
if (attachedWindow != null) {
@@ -1269,6 +1288,12 @@
&& !oldWindow.childTokens.equals(newWindow.childTokens)) {
return true;
}
+ if (!TextUtils.equals(oldWindow.title, newWindow.title)) {
+ return true;
+ }
+ if (oldWindow.accessibilityIdOfAnchor != newWindow.accessibilityIdOfAnchor) {
+ return true;
+ }
return false;
}
diff --git a/services/core/java/com/android/server/wm/DimLayerController.java b/services/core/java/com/android/server/wm/DimLayerController.java
index 97d0ae0..3ec02b9 100644
--- a/services/core/java/com/android/server/wm/DimLayerController.java
+++ b/services/core/java/com/android/server/wm/DimLayerController.java
@@ -183,7 +183,12 @@
for (int i = mState.size() - 1; i >= 0; i--) {
DimLayer.DimLayerUser user = mState.keyAt(i);
- if (user.isFullscreen()) {
+ DimLayerState state = mState.valueAt(i);
+ // We have to check that we are acutally the shared fullscreen layer
+ // for this path. If we began as non fullscreen and became fullscreen
+ // (e.g. Docked stack closing), then we may not be the shared layer
+ // and we have to make sure we always animate the layer.
+ if (user.isFullscreen() && state.dimLayer == mSharedFullScreenDimLayer) {
fullScreen = i;
if (mState.valueAt(i).continueDimming) {
fullScreenAndDimming = i;
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 5212211..28379f4 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -429,6 +429,7 @@
}
if (getDockedStackVisibleForUserLocked() != null) {
mDividerControllerLocked.getTouchRegion(mTmpRect);
+ mTmpRegion.set(mTmpRect);
mTouchExcludeRegion.op(mTmpRegion, Op.UNION);
}
if (mTapDetector != null) {
diff --git a/services/core/java/com/android/server/wm/DockedStackDividerController.java b/services/core/java/com/android/server/wm/DockedStackDividerController.java
index 6741aba..6f7e64f 100644
--- a/services/core/java/com/android/server/wm/DockedStackDividerController.java
+++ b/services/core/java/com/android/server/wm/DockedStackDividerController.java
@@ -41,6 +41,8 @@
import com.android.server.wm.DimLayer.DimLayerUser;
+import java.util.ArrayList;
+
/**
* Keeps information about the docked stack divider.
*/
@@ -87,7 +89,7 @@
private final DimLayer mDimLayer;
private boolean mMinimizedDock;
- private boolean mAnimating;
+ private boolean mAnimatingForMinimizedDockedStack;
private boolean mAnimationStarted;
private long mAnimationStartTime;
private float mAnimationStart;
@@ -96,7 +98,8 @@
private final Interpolator mMinimizedDockInterpolator;
private float mMaximizeMeetFraction;
private final Rect mTouchRegion = new Rect();
- private boolean mAdjustingForIme;
+ private boolean mAnimatingForIme;
+ private boolean mAdjustedForIme;
DockedStackDividerController(WindowManagerService service, DisplayContent displayContent) {
mService = service;
@@ -174,12 +177,11 @@
return mLastVisibility;
}
- void setAdjustingForIme(boolean adjusting) {
- mAdjustingForIme = adjusting;
- }
-
- boolean isAdjustingForIme() {
- return mAdjustingForIme;
+ void setAdjustedForIme(boolean adjusted, boolean animate) {
+ if (mAdjustedForIme != adjusted) {
+ mAnimatingForIme = animate;
+ mAdjustedForIme = adjusted;
+ }
}
void positionDockedStackedDivider(Rect frame) {
@@ -241,6 +243,9 @@
}
}
mDockedStackListeners.finishBroadcast();
+ if (!exists) {
+ setMinimizedDockedStack(false);
+ }
}
void notifyDockedStackMinimizedChanged(boolean minimizedDock, long animDuration) {
@@ -261,6 +266,7 @@
notifyDockedDividerVisibilityChanged(wasVisible());
notifyDockedStackExistsChanged(
mDisplayContent.mService.mStackIdToStack.get(DOCKED_STACK_ID) != null);
+ notifyDockedStackMinimizedChanged(mMinimizedDock, 0 /* animDuration */);
}
void setResizeDimLayer(boolean visible, int targetStackId, float alpha) {
@@ -336,12 +342,14 @@
* @param animate Whether to animate the change.
*/
private void setMinimizedDockedStack(boolean minimizedDock, boolean animate) {
- if (minimizedDock == mMinimizedDock
+ final boolean wasMinimized = mMinimizedDock;
+ mMinimizedDock = minimizedDock;
+ if (minimizedDock == wasMinimized
|| mDisplayContent.getDockedStackVisibleForUserLocked() == null) {
return;
}
- mMinimizedDock = minimizedDock;
+ mAnimatingForIme = false;
if (minimizedDock) {
if (animate) {
startAdjustAnimation(0f, 1f);
@@ -358,7 +366,7 @@
}
private void startAdjustAnimation(float from, float to) {
- mAnimating = true;
+ mAnimatingForMinimizedDockedStack = true;
mAnimationStarted = false;
mAnimationStart = from;
mAnimationTarget = to;
@@ -366,13 +374,13 @@
private void setMinimizedDockedStack(boolean minimized) {
final TaskStack stack = mDisplayContent.getDockedStackVisibleForUserLocked();
+ notifyDockedStackMinimizedChanged(minimized, 0);
if (stack == null) {
return;
}
if (stack.setAdjustedForMinimizedDock(minimized ? 1f : 0f)) {
mService.mWindowPlacerLocked.performSurfacePlacement();
}
- notifyDockedStackMinimizedChanged(minimized, 0);
}
private boolean isAnimationMaximizing() {
@@ -380,10 +388,45 @@
}
public boolean animate(long now) {
- if (!mAnimating) {
+ if (mAnimatingForMinimizedDockedStack) {
+ return animateForMinimizedDockedStack(now);
+ } else if (mAnimatingForIme) {
+ return animateForIme();
+ } else {
return false;
}
+ }
+ private boolean animateForIme() {
+ boolean updated = false;
+ boolean animating = false;
+
+ final ArrayList<TaskStack> stacks = mDisplayContent.getStacks();
+ for (int i = stacks.size() - 1; i >= 0; --i) {
+ final TaskStack stack = stacks.get(i);
+ if (stack != null && stack.isAdjustedForIme()) {
+ updated |= stack.updateAdjustForIme();
+ animating |= stack.isAnimatingForIme();
+ }
+ }
+
+ if (updated) {
+ mService.mWindowPlacerLocked.performSurfacePlacement();
+ }
+
+ if (!animating) {
+ mAnimatingForIme = false;
+ for (int i = stacks.size() - 1; i >= 0; --i) {
+ final TaskStack stack = stacks.get(i);
+ if (stack != null) {
+ stack.clearImeGoingAway();
+ }
+ }
+ }
+ return animating;
+ }
+
+ private boolean animateForMinimizedDockedStack(long now) {
final TaskStack stack = mDisplayContent.getDockedStackVisibleForUserLocked();
if (!mAnimationStarted) {
mAnimationStarted = true;
@@ -406,7 +449,7 @@
}
}
if (t >= 1.0f) {
- mAnimating = false;
+ mAnimatingForMinimizedDockedStack = false;
return false;
} else {
return true;
diff --git a/services/core/java/com/android/server/wm/DragState.java b/services/core/java/com/android/server/wm/DragState.java
index cf27b97..aace5e7 100644
--- a/services/core/java/com/android/server/wm/DragState.java
+++ b/services/core/java/com/android/server/wm/DragState.java
@@ -589,7 +589,7 @@
void overridePointerIconLw(int touchSource) {
mTouchSource = touchSource;
if (isFromSource(InputDevice.SOURCE_MOUSE)) {
- InputManager.getInstance().setPointerIconShape(PointerIcon.STYLE_GRAB);
+ InputManager.getInstance().setPointerIconShape(PointerIcon.STYLE_GRABBING);
}
}
}
diff --git a/services/core/java/com/android/server/wm/InputConsumerImpl.java b/services/core/java/com/android/server/wm/InputConsumerImpl.java
index 0581a16..24783bc 100644
--- a/services/core/java/com/android/server/wm/InputConsumerImpl.java
+++ b/services/core/java/com/android/server/wm/InputConsumerImpl.java
@@ -16,38 +16,33 @@
package com.android.server.wm;
-import android.os.Looper;
import android.os.Process;
import android.view.Display;
import android.view.InputChannel;
-import android.view.InputEventReceiver;
import android.view.WindowManager;
-import android.view.WindowManagerPolicy;
-
import com.android.server.input.InputApplicationHandle;
import com.android.server.input.InputWindowHandle;
-public final class InputConsumerImpl implements WindowManagerPolicy.InputConsumer {
+class InputConsumerImpl {
final WindowManagerService mService;
final InputChannel mServerChannel, mClientChannel;
final InputApplicationHandle mApplicationHandle;
final InputWindowHandle mWindowHandle;
- final InputEventReceiver mInputEventReceiver;
- final int mWindowLayer;
- public InputConsumerImpl(WindowManagerService service, Looper looper,
- InputEventReceiver.Factory inputEventReceiverFactory) {
- String name = "input consumer";
+ InputConsumerImpl(WindowManagerService service, String name, InputChannel inputChannel) {
mService = service;
InputChannel[] channels = InputChannel.openInputChannelPair(name);
mServerChannel = channels[0];
- mClientChannel = channels[1];
+ if (inputChannel != null) {
+ channels[1].transferTo(inputChannel);
+ channels[1].dispose();
+ mClientChannel = inputChannel;
+ } else {
+ mClientChannel = channels[1];
+ }
mService.mInputManager.registerInputChannel(mServerChannel, null);
- mInputEventReceiver = inputEventReceiverFactory.createInputEventReceiver(
- mClientChannel, looper);
-
mApplicationHandle = new InputApplicationHandle(null);
mApplicationHandle.name = name;
mApplicationHandle.dispatchingTimeoutNanos =
@@ -57,8 +52,7 @@
mWindowHandle.name = name;
mWindowHandle.inputChannel = mServerChannel;
mWindowHandle.layoutParamsType = WindowManager.LayoutParams.TYPE_INPUT_CONSUMER;
- mWindowLayer = getLayerLw(mWindowHandle.layoutParamsType);
- mWindowHandle.layer = mWindowLayer;
+ mWindowHandle.layer = getLayerLw(mWindowHandle.layoutParamsType);
mWindowHandle.layoutParamsFlags = 0;
mWindowHandle.dispatchingTimeoutNanos =
WindowManagerService.DEFAULT_INPUT_DISPATCHING_TIMEOUT_NANOS;
@@ -81,21 +75,15 @@
mWindowHandle.frameBottom = dh;
}
- @Override
- public void dismiss() {
- synchronized (mService.mWindowMap) {
- if (mService.removeInputConsumer()) {
- mInputEventReceiver.dispose();
- mService.mInputManager.unregisterInputChannel(mServerChannel);
- mClientChannel.dispose();
- mServerChannel.dispose();
- }
- }
- }
-
private int getLayerLw(int windowType) {
return mService.mPolicy.windowTypeToLayerLw(windowType)
* WindowManagerService.TYPE_LAYER_MULTIPLIER
+ WindowManagerService.TYPE_LAYER_OFFSET;
}
+
+ void disposeChannelsLw() {
+ mService.mInputManager.unregisterInputChannel(mServerChannel);
+ mClientChannel.dispose();
+ mServerChannel.dispose();
+ }
}
diff --git a/services/core/java/com/android/server/wm/InputMonitor.java b/services/core/java/com/android/server/wm/InputMonitor.java
index b702180..eea0e73 100644
--- a/services/core/java/com/android/server/wm/InputMonitor.java
+++ b/services/core/java/com/android/server/wm/InputMonitor.java
@@ -282,6 +282,8 @@
boolean addInputConsumerHandle = mService.mInputConsumer != null;
+ boolean addWallpaperInputConsumerHandle = mService.mWallpaperInputConsumer != null;
+
// Add all windows on the default display.
final int numDisplays = mService.mDisplayContents.size();
final WallpaperController wallpaperController = mService.mWallpaperControllerLocked;
@@ -302,6 +304,14 @@
addInputConsumerHandle = false;
}
+ if (addWallpaperInputConsumerHandle) {
+ if (child.mAttrs.type == WindowManager.LayoutParams.TYPE_WALLPAPER) {
+ // Add the wallpaper input consumer above the first wallpaper window.
+ addInputWindowHandleLw(mService.mWallpaperInputConsumer.mWindowHandle);
+ addWallpaperInputConsumerHandle = false;
+ }
+ }
+
final int flags = child.mAttrs.flags;
final int privateFlags = child.mAttrs.privateFlags;
final int type = child.mAttrs.type;
@@ -329,6 +339,11 @@
}
}
+ if (addWallpaperInputConsumerHandle) {
+ // No wallpaper found, add the wallpaper input consumer at the end.
+ addInputWindowHandleLw(mService.mWallpaperInputConsumer.mWindowHandle);
+ }
+
// Send windows to native code.
mService.mInputManager.setInputWindows(mInputWindowHandles);
diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java
index c0c1ed8..daeb860 100644
--- a/services/core/java/com/android/server/wm/Session.java
+++ b/services/core/java/com/android/server/wm/Session.java
@@ -195,10 +195,8 @@
@Override
public void repositionChild(IWindow window, int left, int top, int right, int bottom,
- int requestedWidth, int requestedHeight,
long deferTransactionUntilFrame, Rect outFrame) {
mService.repositionChild(this, window, left, top, right, bottom,
- requestedWidth, requestedHeight,
deferTransactionUntilFrame, outFrame);
}
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 4e8f19e..eea0ca0 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -425,7 +425,7 @@
if (mFullscreen
|| !StackId.isTaskResizeableByDockedStack(mStack.mStackId)
|| displayContent == null
- || displayContent.getDockedStackLocked() != null) {
+ || displayContent.getDockedStackVisibleForUserLocked() != null) {
return true;
}
return false;
@@ -498,7 +498,15 @@
return;
}
- out.set(mBounds);
+ if (!mFullscreen) {
+ // When minimizing the docked stack when going home, we don't adjust the task bounds
+ // so we need to intersect the task bounds with the stack bounds here.
+ mStack.getBounds(mTmpRect);
+ mTmpRect.intersect(mBounds);
+ out.set(mTmpRect);
+ } else {
+ out.set(mBounds);
+ }
return;
}
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index 8d67771..0225c9b 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -55,6 +55,11 @@
// If the stack should be resized to fullscreen.
private static final boolean FULLSCREEN = true;
+ // When we have a top-bottom split screen, we shift the bottom stack up to accommodate
+ // the IME window. The static flag below controls whether to run animation when the
+ // IME window goes away.
+ private static final boolean ANIMATE_IME_GOING_AWAY = false;
+
/** Unique identifier */
final int mStackId;
@@ -107,6 +112,7 @@
private final Rect mLastContentBounds = new Rect();
private final Rect mTmpAdjustedBounds = new Rect();
private boolean mAdjustedForIme;
+ private boolean mImeGoingAway;
private WindowState mImeWin;
private float mMinimizeAmount;
private final int mDockedStackMinimizeThickness;
@@ -122,6 +128,10 @@
// in which case a second window animation would cause jitter.
private boolean mFreezeMovementAnimations = false;
+ // Temporary storage for the new bounds that should be used after the configuration change.
+ // Will be cleared once the client retrieves the new bounds via getBoundsForNewConfiguration().
+ private final Rect mBoundsAfterRotation = new Rect();
+
TaskStack(WindowManagerService service, int stackId) {
mService = service;
mStackId = stackId;
@@ -337,28 +347,28 @@
setBounds(mTmpRect2);
} else {
mLastUpdateDisplayInfoRotation = newRotation;
- updateBoundsAfterRotation();
+ updateBoundsAfterRotation(true);
}
}
- void onConfigurationChanged() {
+ boolean onConfigurationChanged() {
mLastConfigChangedRotation = getDisplayInfo().rotation;
- updateBoundsAfterRotation();
+ return updateBoundsAfterRotation(false);
}
- void updateBoundsAfterRotation() {
+ boolean updateBoundsAfterRotation(boolean scheduleResize) {
if (mLastConfigChangedRotation != mLastUpdateDisplayInfoRotation) {
// We wait for the rotation values after configuration change and display info. update
// to be equal before updating the bounds due to rotation change otherwise things might
// get out of alignment...
- return;
+ return false;
}
final int newRotation = getDisplayInfo().rotation;
if (mRotation == newRotation) {
// Nothing to do here if the rotation didn't change
- return;
+ return false;
}
mDisplayContent.rotateBounds(mRotation, newRotation, mTmpRect2);
@@ -367,11 +377,22 @@
snapDockedStackAfterRotation(mTmpRect2);
}
- // Post message to inform activity manager of the bounds change simulating
- // a one-way call. We do this to prevent a deadlock between window manager
- // lock and activity manager lock been held.
- mService.mH.obtainMessage(
- RESIZE_STACK, mStackId, 0 /*allowResizeInDockedMode*/, mTmpRect2).sendToTarget();
+ if (scheduleResize) {
+ // Post message to inform activity manager of the bounds change simulating
+ // a one-way call. We do this to prevent a deadlock between window manager
+ // lock and activity manager lock been held.
+ mService.mH.obtainMessage(RESIZE_STACK, mStackId,
+ 0 /*allowResizeInDockedMode*/, mTmpRect2).sendToTarget();
+ } else {
+ mBoundsAfterRotation.set(mTmpRect2);
+ }
+
+ return true;
+ }
+
+ void getBoundsForNewConfiguration(Rect outBounds) {
+ outBounds.set(mBoundsAfterRotation);
+ mBoundsAfterRotation.setEmpty();
}
/**
@@ -796,19 +817,54 @@
void setAdjustedForIme(WindowState imeWin) {
mAdjustedForIme = true;
mImeWin = imeWin;
- if (updateAdjustedBounds()) {
- getDisplayContent().mDividerControllerLocked.setAdjustingForIme(true);
+ mImeGoingAway = false;
+ }
+
+ boolean isAdjustedForIme() {
+ return mAdjustedForIme || mImeGoingAway;
+ }
+ void clearImeGoingAway() {
+ mImeGoingAway = false;
+ }
+
+ boolean isAnimatingForIme() {
+ return mImeWin != null && mImeWin.isAnimatingLw();
+ }
+
+ /**
+ * Update the stack's bounds (crop or position) according to the IME window's
+ * current position. When IME window is animated, the bottom stack is animated
+ * together to track the IME window's current position, and the top stack is
+ * cropped as necessary.
+ *
+ * @return true if a traversal should be performed after the adjustment.
+ */
+ boolean updateAdjustForIme() {
+ boolean stopped = false;
+ if (mImeGoingAway && (!ANIMATE_IME_GOING_AWAY || !isAnimatingForIme())) {
+ mImeWin = null;
+ mAdjustedForIme = false;
+ stopped = true;
}
+ // Make sure to run a traversal when the animation stops so that the stack
+ // is moved to its final position.
+ return updateAdjustedBounds() || stopped;
}
/**
* Resets the adjustment after it got adjusted for the IME.
+ * @param adjustBoundsNow if true, reset and update the bounds immediately and forget about
+ * animations; otherwise, set flag and animates the window away together
+ * with IME window.
*/
- void resetAdjustedForIme() {
- mAdjustedForIme = false;
- mImeWin = null;
- if (updateAdjustedBounds()) {
- getDisplayContent().mDividerControllerLocked.setAdjustingForIme(true);
+ void resetAdjustedForIme(boolean adjustBoundsNow) {
+ if (adjustBoundsNow) {
+ mImeWin = null;
+ mAdjustedForIme = false;
+ mImeGoingAway = false;
+ updateAdjustedBounds();
+ } else {
+ mImeGoingAway |= mAdjustedForIme;
}
}
@@ -828,6 +884,10 @@
}
}
+ boolean isAdjustedForMinimizedDock() {
+ return mMinimizeAmount != 0f;
+ }
+
private boolean adjustForIME(final WindowState imeWin) {
final int dockedSide = getDockSide();
final boolean dockedTopOrBottom = dockedSide == DOCKED_TOP || dockedSide == DOCKED_BOTTOM;
@@ -843,6 +903,12 @@
getDisplayContent().getContentRect(displayContentRect);
contentBounds.set(displayContentRect);
int imeTop = Math.max(imeWin.getDisplayFrameLw().top, contentBounds.top);
+
+ // if IME window is animating, get its actual vertical shown position (but no smaller than
+ // the final target vertical position)
+ if (imeWin.isAnimatingLw()) {
+ imeTop = Math.max(imeTop, imeWin.getShownPositionLw().y);
+ }
imeTop += imeWin.getGivenContentInsetsLw().top;
if (contentBounds.bottom > imeTop) {
contentBounds.bottom = imeTop;
@@ -891,9 +957,11 @@
(int) (minimizeAmount * topInset + (1 - minimizeAmount) * mBounds.bottom);
} else if (dockSide == DOCKED_LEFT) {
mTmpAdjustedBounds.set(mBounds);
+ final int width = mBounds.width();
mTmpAdjustedBounds.right =
(int) (minimizeAmount * mDockedStackMinimizeThickness
+ (1 - minimizeAmount) * mBounds.right);
+ mTmpAdjustedBounds.left = mTmpAdjustedBounds.right - width;
} else if (dockSide == DOCKED_RIGHT) {
mTmpAdjustedBounds.set(mBounds);
mTmpAdjustedBounds.left =
diff --git a/services/core/java/com/android/server/wm/WindowLayersController.java b/services/core/java/com/android/server/wm/WindowLayersController.java
index f76f03f..3bfcf00 100644
--- a/services/core/java/com/android/server/wm/WindowLayersController.java
+++ b/services/core/java/com/android/server/wm/WindowLayersController.java
@@ -191,18 +191,20 @@
}
private void adjustSpecialWindows() {
- int layer = mHighestApplicationLayer + 1;
+ int layer = mHighestApplicationLayer + WINDOW_LAYER_MULTIPLIER;
// For pinned and docked stack window, we want to make them above other windows also when
// these windows are animating.
while (!mDockedWindows.isEmpty()) {
layer = assignAndIncreaseLayerIfNeeded(mDockedWindows.remove(), layer);
}
- // Leave some space here so the dim layer while dismissing docked/fullscreen stack has space
- // below the divider but above the app windows. It needs to be below the divider in because
- // the divider sometimes overlaps the app windows.
- layer++;
layer = assignAndIncreaseLayerIfNeeded(mDockDivider, layer);
+
+ // If we have a dock divider ensure the Input Method is above it.
+ if (mDockDivider != null && mService.mInputMethodWindow != null) {
+ layer = assignAndIncreaseLayerIfNeeded(mService.mInputMethodWindow, layer);
+ }
+
// We know that we will be animating a relaunching window in the near future, which will
// receive a z-order increase. We want the replaced window to immediately receive the same
// treatment, e.g. to be above the dock divider.
@@ -218,11 +220,12 @@
private int assignAndIncreaseLayerIfNeeded(WindowState win, int layer) {
if (win != null) {
assignAnimLayer(win, layer);
- layer++;
+ // Make sure we leave space inbetween normal windows for dims and such.
+ layer += WINDOW_LAYER_MULTIPLIER;
}
return layer;
}
-
+
private void assignAnimLayer(WindowState w, int layer) {
w.mLayer = layer;
w.mWinAnimator.mAnimLayer = w.mLayer + w.getAnimLayerAdjustment() +
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 5771d69..fd6617a 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -125,6 +125,7 @@
import com.android.internal.app.IAssistScreenshotReceiver;
import com.android.internal.os.IResultReceiver;
import com.android.internal.policy.IShortcutService;
+import com.android.internal.util.ArrayUtils;
import com.android.internal.util.FastPrintWriter;
import com.android.internal.view.IInputContext;
import com.android.internal.view.IInputMethodClient;
@@ -407,6 +408,11 @@
InputConsumerImpl mInputConsumer;
/**
+ * The input consumer added to the window manager before all wallpaper windows.
+ */
+ InputConsumerImpl mWallpaperInputConsumer;
+
+ /**
* Windows that are being resized. Used so we can tell the client about
* the resize after closing the transaction in which we resized the
* underlying surface.
@@ -510,6 +516,8 @@
private final SparseIntArray mTmpTaskIds = new SparseIntArray();
+ private final ArrayList<Integer> mChangedStackList = new ArrayList();
+
boolean mForceResizableTasks = false;
int getDragLayerLocked() {
@@ -1365,7 +1373,7 @@
// needs to sit above the dock divider, so it doesn't get cut in half. We make the dock
// divider be a target for IME, so this relationship can occur naturally.
if (fl == 0 || fl == (FLAG_NOT_FOCUSABLE|FLAG_ALT_FOCUSABLE_IM)
- || type == TYPE_APPLICATION_STARTING || type == TYPE_DOCK_DIVIDER) {
+ || type == TYPE_APPLICATION_STARTING) {
if (DEBUG_INPUT_METHOD) {
Slog.i(TAG_WM, "isVisibleOrAdding " + w + ": " + w.isVisibleOrAdding());
if (!w.isVisibleOrAdding()) {
@@ -2531,7 +2539,6 @@
void repositionChild(Session session, IWindow client,
int left, int top, int right, int bottom,
- int requestedWidth, int requestedHeight,
long deferTransactionUntilFrame, Rect outFrame) {
Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "repositionChild");
long origId = Binder.clearCallingIdentity();
@@ -2547,7 +2554,6 @@
"repositionChild called but window is not"
+ "attached to a parent win=" + win);
}
- win.setRequestedSize(requestedWidth, requestedHeight);
win.mAttrs.x = left;
win.mAttrs.y = top;
@@ -2604,8 +2610,6 @@
== PackageManager.PERMISSION_GRANTED;
long origId = Binder.clearCallingIdentity();
- final boolean preserveGeometry = (attrs != null) && (attrs.privateFlags &
- WindowManager.LayoutParams.PRIVATE_FLAG_PRESERVE_GEOMETRY) != 0;
synchronized(mWindowMap) {
WindowState win = windowForClientLocked(session, client, false);
if (win == null) {
@@ -2613,7 +2617,7 @@
}
WindowStateAnimator winAnimator = win.mWinAnimator;
- if (!preserveGeometry && viewVisibility != View.GONE) {
+ if (viewVisibility != View.GONE) {
win.setRequestedSize(requestedWidth, requestedHeight);
}
@@ -2662,9 +2666,7 @@
if ((attrChanges & WindowManager.LayoutParams.ALPHA_CHANGED) != 0) {
winAnimator.mAlpha = attrs.alpha;
}
- if (!preserveGeometry) {
- win.setWindowScale(win.mRequestedWidth, win.mRequestedHeight);
- }
+ win.setWindowScale(win.mRequestedWidth, win.mRequestedHeight);
boolean imMayMove = (flagChanges & (FLAG_ALT_FOCUSABLE_IM | FLAG_NOT_FOCUSABLE)) != 0;
final boolean isDefaultDisplay = win.isDefaultDisplay();
@@ -3399,7 +3401,8 @@
}
}
- if (isStackVisibleLocked(DOCKED_STACK_ID)
+ if ((isStackVisibleLocked(DOCKED_STACK_ID)
+ && !mStackIdToStack.get(DOCKED_STACK_ID).isAdjustedForMinimizedDock())
|| isStackVisibleLocked(FREEFORM_WORKSPACE_STACK_ID)) {
// We don't let app affect the system orientation when in freeform or docked mode since
// they don't occupy the entire display and their request can conflict with other apps.
@@ -3581,7 +3584,7 @@
}
@Override
- public void setNewConfiguration(Configuration config) {
+ public int[] setNewConfiguration(Configuration config) {
if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
"setNewConfiguration()")) {
throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
@@ -3593,16 +3596,30 @@
mWaitingForConfig = false;
mLastFinishedFreezeSource = "new-config";
}
- onConfigurationChanged();
- mWindowPlacerLocked.performSurfacePlacement();
+ return onConfigurationChanged();
}
}
- private void onConfigurationChanged() {
+ @Override
+ public Rect getBoundsForNewConfiguration(int stackId) {
+ synchronized(mWindowMap) {
+ final TaskStack stack = mStackIdToStack.get(stackId);
+ final Rect outBounds = new Rect();
+ stack.getBoundsForNewConfiguration(outBounds);
+ return outBounds;
+ }
+ }
+
+ private int[] onConfigurationChanged() {
+ mChangedStackList.clear();
for (int stackNdx = mStackIdToStack.size() - 1; stackNdx >= 0; stackNdx--) {
final TaskStack stack = mStackIdToStack.valueAt(stackNdx);
- stack.onConfigurationChanged();
+ if (stack.onConfigurationChanged()) {
+ mChangedStackList.add(stack.mStackId);
+ }
}
+ return mChangedStackList.isEmpty() ?
+ null : ArrayUtils.convertToIntArray(mChangedStackList);
}
@Override
@@ -4118,6 +4135,14 @@
for (int i = 0; i < windowsCount; i++) {
WindowState win = wtoken.allAppWindows.get(i);
if (win == wtoken.startingWindow) {
+ // Starting window that's exiting will be removed when the animation
+ // finishes. Mark all relevant flags for that finishExit will proceed
+ // all the way to actually remove it.
+ if (!visible && win.isVisibleNow() && wtoken.mAppAnimator.isAnimating()) {
+ win.mAnimatingExit = true;
+ win.mRemoveOnExit = true;
+ win.mWindowRemovalAllowed = true;
+ }
continue;
}
@@ -6069,7 +6094,7 @@
int bottom = wf.bottom - cr.bottom;
frame.union(left, top, right, bottom);
ws.getVisibleBounds(stackBounds);
- if (!frame.intersect(stackBounds)) {
+ if (!Rect.intersects(frame, stackBounds)) {
// Set frame empty if there's no intersection.
frame.setEmpty();
}
@@ -7380,8 +7405,9 @@
final WindowState imeWin = mInputMethodWindow;
final TaskStack focusedStack =
mCurrentFocus != null ? mCurrentFocus.getStack() : null;
+ final boolean dockVisible = isStackVisibleLocked(DOCKED_STACK_ID);
if (imeWin != null && imeWin.isVisibleLw() && imeWin.isDisplayedLw()
- && isStackVisibleLocked(DOCKED_STACK_ID)
+ && dockVisible
&& focusedStack != null
&& focusedStack.getDockSide() == DOCKED_BOTTOM){
final ArrayList<TaskStack> stacks = displayContent.getStacks();
@@ -7391,12 +7417,14 @@
stack.setAdjustedForIme(imeWin);
}
}
+ displayContent.mDividerControllerLocked.setAdjustedForIme(true, true);
} else {
final ArrayList<TaskStack> stacks = displayContent.getStacks();
for (int i = stacks.size() - 1; i >= 0; --i) {
final TaskStack stack = stacks.get(i);
- stack.resetAdjustedForIme();
+ stack.resetAdjustedForIme(!dockVisible);
}
+ displayContent.mDividerControllerLocked.setAdjustedForIme(false, dockVisible);
}
}
@@ -9627,13 +9655,37 @@
}
}
+ private static final class HideNavInputConsumer extends InputConsumerImpl
+ implements WindowManagerPolicy.InputConsumer {
+ private final InputEventReceiver mInputEventReceiver;
+
+ HideNavInputConsumer(WindowManagerService service, Looper looper,
+ InputEventReceiver.Factory inputEventReceiverFactory) {
+ super(service, "input consumer", null);
+ mInputEventReceiver = inputEventReceiverFactory.createInputEventReceiver(
+ mClientChannel, looper);
+ }
+
+ @Override
+ public void dismiss() {
+ if (mService.removeInputConsumer()) {
+ synchronized (mService.mWindowMap) {
+ mInputEventReceiver.dispose();
+ disposeChannelsLw();
+ }
+ }
+ }
+ }
+
@Override
- public InputConsumerImpl addInputConsumer(Looper looper,
+ public WindowManagerPolicy.InputConsumer addInputConsumer(Looper looper,
InputEventReceiver.Factory inputEventReceiverFactory) {
synchronized (mWindowMap) {
- mInputConsumer = new InputConsumerImpl(this, looper, inputEventReceiverFactory);
+ HideNavInputConsumer inputConsumerImpl = new HideNavInputConsumer(
+ this, looper, inputEventReceiverFactory);
+ mInputConsumer = inputConsumerImpl;
mInputMonitor.updateInputWindowsLw(true);
- return mInputConsumer;
+ return inputConsumerImpl;
}
}
@@ -9648,6 +9700,24 @@
}
}
+ public void createWallpaperInputConsumer(InputChannel inputChannel) {
+ synchronized (mWindowMap) {
+ mWallpaperInputConsumer = new InputConsumerImpl(this, "wallpaper input", inputChannel);
+ mWallpaperInputConsumer.mWindowHandle.hasWallpaper = true;
+ mInputMonitor.updateInputWindowsLw(true);
+ }
+ }
+
+ public void removeWallpaperInputConsumer() {
+ synchronized (mWindowMap) {
+ if (mWallpaperInputConsumer != null) {
+ mWallpaperInputConsumer.disposeChannelsLw();
+ mWallpaperInputConsumer = null;
+ mInputMonitor.updateInputWindowsLw(true);
+ }
+ }
+ }
+
@Override
public boolean hasNavigationBar() {
return mPolicy.hasNavigationBar();
@@ -10725,6 +10795,19 @@
}
@Override
+ public void getMagnificationRegions(@NonNull Region outMagnified,
+ @NonNull Region outAvailable) {
+ synchronized (mWindowMap) {
+ if (mAccessibilityController != null) {
+ mAccessibilityController.getMagnificationRegionsLocked(
+ outMagnified, outAvailable);
+ } else {
+ throw new IllegalStateException("Magnification callbacks not set!");
+ }
+ }
+ }
+
+ @Override
public MagnificationSpec getCompatibleMagnificationSpecForWindow(IBinder windowToken) {
synchronized (mWindowMap) {
WindowState windowState = mWindowMap.get(windowToken);
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 0866c03..ec86a0190 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -642,7 +642,7 @@
mHaveFrame = true;
final Task task = getTask();
- final boolean fullscreenTask = !inMultiWindowMode();
+ final boolean fullscreenTask = !isInMultiWindowMode();
final boolean windowsAreFloating = task != null && task.isFloating();
// If the task has temp inset bounds set, we have to make sure all its windows uses
@@ -670,10 +670,18 @@
mContainingFrame.bottom = mContainingFrame.top + frozen.height();
}
final WindowState imeWin = mService.mInputMethodWindow;
- if (imeWin != null && imeWin.isVisibleNow() && mService.mInputMethodTarget == this
- && mContainingFrame.bottom > cf.bottom) {
- // IME is up and obscuring this window. Adjust the window position so it is visible.
- mContainingFrame.top -= mContainingFrame.bottom - cf.bottom;
+ // IME is up and obscuring this window. Adjust the window position so it is visible.
+ if (imeWin != null && imeWin.isVisibleNow() && mService.mInputMethodTarget == this) {
+ if (windowsAreFloating && mContainingFrame.bottom > cf.bottom) {
+ // In freeform we want to move the top up directly.
+ // TODO: Investigate why this is cf not pf.
+ mContainingFrame.top -= mContainingFrame.bottom - cf.bottom;
+ } else if (mContainingFrame.bottom > pf.bottom) {
+ // But in docked we want to behave like fullscreen
+ // and behave as if the task were given smaller bounds
+ // for the purposes of layout.
+ mContainingFrame.bottom = pf.bottom;
+ }
}
if (windowsAreFloating) {
@@ -1878,6 +1886,11 @@
}
private boolean shouldSaveSurface() {
+ if (mWinAnimator.mSurfaceController == null) {
+ // Don't bother if the surface controller is gone for any reason.
+ return false;
+ }
+
if ((mAttrs.flags & FLAG_SECURE) != 0) {
// We don't save secure surfaces since their content shouldn't be shown while the app
// isn't on screen and content might leak through during the transition animation with
@@ -1951,10 +1964,18 @@
return;
}
mSurfaceSaved = false;
- setHasSurface(true);
- mWinAnimator.mDrawState = WindowStateAnimator.READY_TO_SHOW;
- if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) {
- Slog.v(TAG, "Restoring saved surface: " + this);
+ if (mWinAnimator.mSurfaceController != null) {
+ setHasSurface(true);
+ mWinAnimator.mDrawState = WindowStateAnimator.READY_TO_SHOW;
+
+ if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) {
+ Slog.v(TAG, "Restoring saved surface: " + this);
+ }
+ } else {
+ // mSurfaceController shouldn't be null if mSurfaceSaved was still true at
+ // this point. Even if we destroyed the saved surface because of rotation
+ // or resize, mSurfaceSaved flag should have been cleared. So this is a wtf.
+ Slog.wtf(TAG, "Failed to restore saved surface: surface gone! " + this);
}
}
@@ -2226,7 +2247,7 @@
}
@Override
- public boolean inMultiWindowMode() {
+ public boolean isInMultiWindowMode() {
final Task task = getTask();
return task != null && !task.isFullscreen();
}
@@ -2527,7 +2548,7 @@
final int pw = mContainingFrame.width();
final int ph = mContainingFrame.height();
final Task task = getTask();
- final boolean nonFullscreenTask = inMultiWindowMode();
+ final boolean nonFullscreenTask = isInMultiWindowMode();
final boolean fitToDisplay = task != null && !task.isFloating() && !layoutInParentFrame();
float x, y;
int w,h;
@@ -2572,7 +2593,7 @@
y = mAttrs.y;
}
- if (nonFullscreenTask) {
+ if (nonFullscreenTask && !layoutInParentFrame()) {
// Make sure window fits in containing frame since it is in a non-fullscreen task as
// required by {@link Gravity#apply} call.
w = Math.min(w, pw);
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 1e103f0..8fd8bc0 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -967,13 +967,15 @@
if (appTransformation != null) {
tmpMatrix.postConcat(appTransformation.getMatrix());
}
+
+ // The translation that applies the position of the window needs to be applied at the
+ // end in case that other translations include scaling. Otherwise the scaling will
+ // affect this translation. But it needs to be set before the screen rotation animation
+ // so the pivot point is at the center of the screen for all windows.
+ tmpMatrix.postTranslate(frame.left + mWin.mXOffset, frame.top + mWin.mYOffset);
if (screenAnimation) {
tmpMatrix.postConcat(screenRotationAnimation.getEnterTransformation().getMatrix());
}
- // The translation that applies the position of the window needs to be applied at the
- // end in case that other translations include scaling. Otherwise the scaling will
- // affect this translation.
- tmpMatrix.postTranslate(frame.left + mWin.mXOffset, frame.top + mWin.mYOffset);
//TODO (multidisplay): Magnification is supported only for the default display.
if (mService.mAccessibilityController != null && displayId == DEFAULT_DISPLAY) {
diff --git a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
index 3b0081d..eda2f39 100644
--- a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
+++ b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
@@ -693,16 +693,14 @@
// currently animating... let's do something.
final int left = w.mFrame.left;
final int top = w.mFrame.top;
- final boolean adjustedForMinimizedDockedStack = w.getTask() != null &&
- w.getTask().mStack.isAdjustedForMinimizedDockedStack();
+ final boolean adjustedForMinimizedDockOrIme = task != null
+ && (task.mStack.isAdjustedForMinimizedDockedStack()
+ || task.mStack.isAdjustedForIme());
if ((w.mAttrs.privateFlags & PRIVATE_FLAG_NO_MOVE_ANIMATION) == 0
- && !w.isDragResizing() && !adjustedForMinimizedDockedStack
+ && !w.isDragResizing() && !adjustedForMinimizedDockOrIme
&& (task == null || !w.getTask().mStack.getFreezeMovementAnimations())
&& !w.mWinAnimator.mLastHidden) {
winAnimator.setMoveAnimation(left, top);
- } else if (w.mAttrs.type == TYPE_DOCK_DIVIDER &&
- displayContent.getDockedDividerController().isAdjustingForIme()) {
- winAnimator.setMoveAnimation(left, top);
}
//TODO (multidisplay): Accessibility supported only for the default display.
@@ -819,8 +817,6 @@
mService.updateResizingWindows(w);
}
- displayContent.getDockedDividerController().setAdjustingForIme(false);
-
mService.mDisplayManagerInternal.setDisplayProperties(displayId,
mDisplayHasContent,
mPreferredRefreshRate,
@@ -864,6 +860,10 @@
mService.mInputConsumer.layout(dw, dh);
}
+ if (mService.mWallpaperInputConsumer != null) {
+ mService.mWallpaperInputConsumer.layout(dw, dh);
+ }
+
final int N = windows.size();
int i;
diff --git a/services/core/jni/com_android_server_HardwarePropertiesManagerService.cpp b/services/core/jni/com_android_server_HardwarePropertiesManagerService.cpp
index ec5e8c9..14d50ce 100644
--- a/services/core/jni/com_android_server_HardwarePropertiesManagerService.cpp
+++ b/services/core/jni/com_android_server_HardwarePropertiesManagerService.cpp
@@ -36,7 +36,8 @@
enum {
TEMPERATURE_CURRENT = 0,
TEMPERATURE_THROTTLING = 1,
- TEMPERATURE_SHUTDOWN = 2
+ TEMPERATURE_SHUTDOWN = 2,
+ TEMPERATURE_THROTTLING_BELOW_VR_MIN = 3
};
static struct {
@@ -127,6 +128,13 @@
values[length++] = list[i].shutdown_threshold;
}
break;
+ case TEMPERATURE_THROTTLING_BELOW_VR_MIN:
+ if (list[i].vr_throttling_threshold == UNKNOWN_TEMPERATURE) {
+ values[length++] = gUndefinedTemperature;
+ } else {
+ values[length++] = list[i].vr_throttling_threshold;
+ }
+ break;
}
}
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 7da0a9a..d68352d 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -136,6 +136,7 @@
import com.android.internal.statusbar.IStatusBarService;
import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.JournaledFile;
+import com.android.internal.util.ParcelableString;
import com.android.internal.util.Preconditions;
import com.android.internal.util.XmlUtils;
import com.android.internal.widget.LockPatternUtils;
@@ -184,12 +185,16 @@
private static final String DEVICE_POLICIES_XML = "device_policies.xml";
+ private static final String TAG_ACCEPTED_CA_CERTIFICATES = "accepted-ca-certificate";
+
private static final String TAG_LOCK_TASK_COMPONENTS = "lock-task-component";
private static final String TAG_STATUS_BAR = "statusbar";
private static final String ATTR_DISABLED = "disabled";
+ private static final String ATTR_NAME = "name";
+
private static final String DO_NOT_ASK_CREDENTIALS_ON_BOOT_XML =
"do-not-ask-credentials-on-boot";
@@ -420,6 +425,8 @@
final ArrayList<ActiveAdmin> mAdminList = new ArrayList<>();
final ArrayList<ComponentName> mRemovingAdmins = new ArrayList<>();
+ final ArraySet<String> mAcceptedCaCertificates = new ArraySet<>();
+
// This is the list of component allowed to start lock task mode.
List<String> mLockTaskPackages = new ArrayList<>();
@@ -483,7 +490,8 @@
}
if (Intent.ACTION_BOOT_COMPLETED.equals(action)
|| KeyChain.ACTION_STORAGE_CHANGED.equals(action)) {
- new MonitoringCertNotificationTask().execute(intent);
+ int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_ALL);
+ new MonitoringCertNotificationTask().execute(userId);
}
if (Intent.ACTION_USER_ADDED.equals(action)) {
disableSecurityLoggingIfNotCompliant();
@@ -654,8 +662,8 @@
String shortSupportMessage = null;
String longSupportMessage = null;
- // Background color of confirm credentials screen. Default: gray.
- static final int DEF_ORGANIZATION_COLOR = Color.GRAY;
+ // Background color of confirm credentials screen. Default: teal.
+ static final int DEF_ORGANIZATION_COLOR = Color.parseColor("#00796B");
int organizationColor = DEF_ORGANIZATION_COLOR;
// Default title of confirm credentials screen
@@ -1480,6 +1488,12 @@
return "/data/system/";
}
+ void registerContentObserver(Uri uri, boolean notifyForDescendents,
+ ContentObserver observer, int userHandle) {
+ mContext.getContentResolver().registerContentObserver(uri, notifyForDescendents,
+ observer, userHandle);
+ }
+
int settingsSecureGetIntForUser(String name, int def, int userHandle) {
return Settings.Secure.getIntForUser(mContext.getContentResolver(),
name, def, userHandle);
@@ -2215,6 +2229,12 @@
out.endTag(null, "active-password");
}
+ for (int i = 0; i < policy.mAcceptedCaCertificates.size(); i++) {
+ out.startTag(null, TAG_ACCEPTED_CA_CERTIFICATES);
+ out.attribute(null, ATTR_NAME, policy.mAcceptedCaCertificates.valueAt(i));
+ out.endTag(null, TAG_ACCEPTED_CA_CERTIFICATES);
+ }
+
for (int i=0; i<policy.mLockTaskPackages.size(); i++) {
String component = policy.mLockTaskPackages.get(i);
out.startTag(null, TAG_LOCK_TASK_COMPONENTS);
@@ -2381,6 +2401,8 @@
parser.getAttributeValue(null, "symbols"));
policy.mActivePasswordNonLetter = Integer.parseInt(
parser.getAttributeValue(null, "nonletter"));
+ } else if (TAG_ACCEPTED_CA_CERTIFICATES.equals(tag)) {
+ policy.mAcceptedCaCertificates.add(parser.getAttributeValue(null, ATTR_NAME));
} else if (TAG_LOCK_TASK_COMPONENTS.equals(tag)) {
policy.mLockTaskPackages.add(parser.getAttributeValue(null, "name"));
} else if (TAG_STATUS_BAR.equals(tag)) {
@@ -2536,7 +2558,7 @@
onStartUser(UserHandle.USER_SYSTEM);
// Register an observer for watching for user setup complete.
- new SetupContentObserver(mHandler).register(mContext.getContentResolver());
+ new SetupContentObserver(mHandler).register();
// Initialize the user setup state, to handle the upgrade case.
updateUserSetupComplete();
@@ -2632,17 +2654,17 @@
}
}
- private class MonitoringCertNotificationTask extends AsyncTask<Intent, Void, Void> {
+ private class MonitoringCertNotificationTask extends AsyncTask<Integer, Void, Void> {
@Override
- protected Void doInBackground(Intent... params) {
- int userHandle = params[0].getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_ALL);
+ protected Void doInBackground(Integer... params) {
+ int userHandle = params[0];
if (userHandle == UserHandle.USER_ALL) {
for (UserInfo userInfo : mUserManager.getUsers()) {
manageNotification(userInfo.getUserHandle());
}
} else {
- manageNotification(new UserHandle(userHandle));
+ manageNotification(UserHandle.of(userHandle));
}
return null;
}
@@ -2652,25 +2674,27 @@
return;
}
- // Call out to KeyChain to check for user-added CAs
- boolean hasCert = false;
+ // Call out to KeyChain to check for CAs which are waiting for approval.
+ final List<String> pendingCertificates;
try {
- KeyChainConnection kcs = KeyChain.bindAsUser(mContext, userHandle);
- try {
- if (!kcs.getService().getUserCaAliases().getList().isEmpty()) {
- hasCert = true;
- }
- } catch (RemoteException e) {
- Log.e(LOG_TAG, "Could not connect to KeyChain service", e);
- } finally {
- kcs.close();
- }
- } catch (InterruptedException e) {
- Thread.currentThread().interrupt();
- } catch (RuntimeException | AssertionError e) {
- Log.e(LOG_TAG, "Could not connect to KeyChain service", e);
+ pendingCertificates = getInstalledCaCertificates(userHandle);
+ } catch (RemoteException | RuntimeException e) {
+ Log.e(LOG_TAG, "Could not retrieve certificates from KeyChain service", e);
+ return;
}
- if (!hasCert) {
+
+ synchronized (DevicePolicyManagerService.this) {
+ final DevicePolicyData policy = getUserData(userHandle.getIdentifier());
+
+ // Remove deleted certificates. Flush xml if necessary.
+ if (policy.mAcceptedCaCertificates.retainAll(pendingCertificates)) {
+ saveSettingsLocked(userHandle.getIdentifier());
+ }
+ // Trim to approved certificates.
+ pendingCertificates.removeAll(policy.mAcceptedCaCertificates);
+ }
+
+ if (pendingCertificates.isEmpty()) {
mInjector.getNotificationManager().cancelAsUser(
null, MONITORING_CERT_NOTIFICATION_ID, userHandle);
return;
@@ -2701,7 +2725,8 @@
final Context userContext;
try {
- userContext = mContext.createPackageContextAsUser("android", 0, userHandle);
+ final String packageName = mContext.getPackageName();
+ userContext = mContext.createPackageContextAsUser(packageName, 0, userHandle);
} catch (PackageManager.NameNotFoundException e) {
Log.e(LOG_TAG, "Create context as " + userHandle + " failed", e);
return;
@@ -2720,6 +2745,29 @@
mInjector.getNotificationManager().notifyAsUser(
null, MONITORING_CERT_NOTIFICATION_ID, noti, userHandle);
}
+
+ private List<String> getInstalledCaCertificates(UserHandle userHandle)
+ throws RemoteException, RuntimeException {
+ KeyChainConnection conn = null;
+ try {
+ conn = KeyChain.bindAsUser(mContext, userHandle);
+ List<ParcelableString> aliases = conn.getService().getUserCaAliases().getList();
+ List<String> result = new ArrayList<>(aliases.size());
+ for (int i = 0; i < aliases.size(); i++) {
+ result.add(aliases.get(i).string);
+ }
+ return result;
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ return null;
+ } catch (AssertionError e) {
+ throw new RuntimeException(e);
+ } finally {
+ if (conn != null) {
+ conn.close();
+ }
+ }
+ }
}
/**
@@ -2757,6 +2805,10 @@
&& getActiveAdminUncheckedLocked(adminReceiver, userHandle) != null) {
throw new IllegalArgumentException("Admin is already added");
}
+ if (policy.mRemovingAdmins.contains(adminReceiver)) {
+ throw new IllegalArgumentException(
+ "Trying to set an admin which is being removed");
+ }
ActiveAdmin newAdmin = new ActiveAdmin(info, /* parent */ false);
policy.mAdminMap.put(adminReceiver, newAdmin);
int replaceIndex = -1;
@@ -3692,32 +3744,26 @@
final int callingUid = mInjector.binderGetCallingUid();
final int userHandle = mInjector.userHandleGetCallingUserId();
- if (getCredentialOwner(userHandle, /* parent */ false) != userHandle) {
- throw new SecurityException("You can not change password for this profile because"
- + " it shares the password with the owner profile");
- }
-
String password = passwordOrNull != null ? passwordOrNull : "";
+ // Password resetting to empty/null is not allowed for managed profiles.
+ if (TextUtils.isEmpty(password)) {
+ enforceNotManagedProfile(userHandle, "clear the active password");
+ }
+
int quality;
synchronized (this) {
- // If caller has PO (or DO), it can clear the password, so see if that's the case
- // first.
+ // If caller has PO (or DO) it can change the password, so see if that's the case first.
ActiveAdmin admin = getActiveAdminWithPolicyForUidLocked(
null, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER, callingUid);
if (admin == null) {
// Otherwise, make sure the caller has any active admin with the right policy.
admin = getActiveAdminForCallerLocked(null,
DeviceAdminInfo.USES_POLICY_RESET_PASSWORD);
- }
- final ComponentName adminComponent = admin.info.getComponent();
-
- // As of N, only profile owners and device owners can reset the password.
- if (!(isProfileOwner(adminComponent, userHandle)
- || isDeviceOwner(adminComponent, userHandle))) {
final boolean preN = getTargetSdk(admin.info.getPackageName(), userHandle)
<= android.os.Build.VERSION_CODES.M;
+
// As of N, password resetting to empty/null is not allowed anymore.
// TODO Should we allow DO/PO to set an empty password?
if (TextUtils.isEmpty(password)) {
@@ -3846,6 +3892,9 @@
// back in to the service.
final long ident = mInjector.binderClearCallingIdentity();
try {
+ if (isManagedProfile(userHandle)) {
+ mLockPatternUtils.setSeparateProfileChallengeEnabled(userHandle, true);
+ }
if (!TextUtils.isEmpty(password)) {
mLockPatternUtils.saveLockPassword(password, null, quality, userHandle);
} else {
@@ -4070,6 +4119,29 @@
}
@Override
+ public boolean approveCaCert(String alias, int userId, boolean approval) {
+ enforceManageUsers();
+ synchronized (this) {
+ Set<String> certs = getUserData(userId).mAcceptedCaCertificates;
+ boolean changed = (approval ? certs.add(alias) : certs.remove(alias));
+ if (!changed) {
+ return false;
+ }
+ saveSettingsLocked(userId);
+ }
+ new MonitoringCertNotificationTask().execute(userId);
+ return true;
+ }
+
+ @Override
+ public boolean isCaCertApproved(String alias, int userId) {
+ enforceManageUsers();
+ synchronized (this) {
+ return getUserData(userId).mAcceptedCaCertificates.contains(alias);
+ }
+ }
+
+ @Override
public boolean installCaCert(ComponentName admin, byte[] certBuffer) throws RemoteException {
enforceCanManageCaCerts(admin);
@@ -4138,8 +4210,8 @@
}
@Override
- public boolean installKeyPair(ComponentName who, byte[] privKey, byte[] cert, String alias,
- boolean requestAccess) {
+ public boolean installKeyPair(ComponentName who, byte[] privKey, byte[] cert, byte[] chain,
+ String alias, boolean requestAccess) {
enforceCanManageInstalledKeys(who);
final int callingUid = mInjector.binderGetCallingUid();
@@ -4149,7 +4221,7 @@
KeyChain.bindAsUser(mContext, UserHandle.getUserHandleForUid(callingUid));
try {
IKeyChainService keyChain = keyChainConnection.getService();
- if (!keyChain.installKeyPair(privKey, cert, alias)) {
+ if (!keyChain.installKeyPair(privKey, cert, chain, alias)) {
return false;
}
if (requestAccess) {
@@ -4868,10 +4940,24 @@
// we start using it for different purposes.
ensureCallerPackage(callerPackage);
+ final ApplicationInfo ai;
+ try {
+ ai = mIPackageManager.getApplicationInfo(callerPackage, 0, userHandle);
+ } catch (RemoteException e) {
+ throw new SecurityException(e);
+ }
+
+ boolean legacyApp = false;
+ if (ai.targetSdkVersion <= Build.VERSION_CODES.M) {
+ legacyApp = true;
+ } else if ("com.google.android.apps.enterprise.dmagent".equals(ai.packageName)
+ && ai.versionCode == 697) {
+ // TODO: STOPSHIP remove this (revert ag/895987) once a new prebuilt is dropped
+ legacyApp = true;
+ }
+
final int rawStatus = getEncryptionStatus();
- if ((rawStatus == DevicePolicyManager.ENCRYPTION_STATUS_ACTIVE_PER_USER)
- && (callerPackage != null)
- && (getTargetSdk(callerPackage, userHandle) <= VERSION_CODES.M)) {
+ if ((rawStatus == DevicePolicyManager.ENCRYPTION_STATUS_ACTIVE_PER_USER) && legacyApp) {
return DevicePolicyManager.ENCRYPTION_STATUS_ACTIVE;
}
return rawStatus;
@@ -5682,26 +5768,25 @@
}
@Override
- public boolean setDeviceOwnerLockScreenInfo(ComponentName who, String info) {
+ public void setDeviceOwnerLockScreenInfo(ComponentName who, CharSequence info) {
Preconditions.checkNotNull(who, "ComponentName is null");
if (!mHasFeature) {
- return false;
+ return;
}
synchronized (this) {
getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
long token = mInjector.binderClearCallingIdentity();
try {
- mLockPatternUtils.setDeviceOwnerInfo(info);
+ mLockPatternUtils.setDeviceOwnerInfo(info != null ? info.toString() : null);
} finally {
mInjector.binderRestoreCallingIdentity(token);
}
- return true;
}
}
@Override
- public String getDeviceOwnerLockScreenInfo() {
+ public CharSequence getDeviceOwnerLockScreenInfo() {
return mLockPatternUtils.getDeviceOwnerInfo();
}
@@ -5783,8 +5868,7 @@
transitionCheckNeeded = false;
} else {
// For all other cases, caller must have MANAGE_PROFILE_AND_DEVICE_OWNERS.
- mContext.enforceCallingOrSelfPermission(
- android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS, null);
+ enforceCanManageProfileAndDeviceOwners();
}
final DevicePolicyData policyData = getUserData(userHandle);
@@ -5977,8 +6061,7 @@
}
return;
}
- mContext.enforceCallingOrSelfPermission(
- android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS, null);
+ enforceCanManageProfileAndDeviceOwners();
if (hasUserSetupCompleted(userHandle) && !isCallerWithSystemUid()) {
throw new IllegalStateException("Cannot set the profile owner on a user which is "
+ "already set-up");
@@ -5993,8 +6076,7 @@
int callingUid = mInjector.binderGetCallingUid();
boolean isAdb = callingUid == Process.SHELL_UID || callingUid == Process.ROOT_UID;
if (!isAdb) {
- mContext.enforceCallingOrSelfPermission(
- android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS, null);
+ enforceCanManageProfileAndDeviceOwners();
}
final int code = checkSetDeviceOwnerPreCondition(userId, isAdb);
@@ -6650,6 +6732,9 @@
}
synchronized (this) {
ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
+ if (admin == null) {
+ return false;
+ }
if (admin.permittedAccessiblityServices == null) {
return true;
}
@@ -6820,6 +6905,9 @@
}
synchronized (this) {
ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
+ if (admin == null) {
+ return false;
+ }
if (admin.permittedInputMethods == null) {
return true;
}
@@ -7002,7 +7090,7 @@
}
@Override
- public boolean getPackageSuspended(ComponentName who, String packageName) {
+ public boolean isPackageSuspended(ComponentName who, String packageName) {
Preconditions.checkNotNull(who, "ComponentName is null");
int callingUserId = UserHandle.getCallingUserId();
synchronized (this) {
@@ -7090,19 +7178,30 @@
}
@Override
- public Bundle getUserRestrictions(ComponentName who, int userHandle) {
+ public Bundle getUserRestrictions(ComponentName who) {
+ if (!mHasFeature) {
+ return null;
+ }
+ Preconditions.checkNotNull(who, "ComponentName is null");
+ synchronized (this) {
+ final ActiveAdmin activeAdmin = getActiveAdminForCallerLocked(who,
+ DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+ return activeAdmin.userRestrictions;
+ }
+ }
+
+ @Override
+ public Bundle getUserRestrictionsForUser(ComponentName who, int userHandle) {
+ if (!mHasFeature) {
+ return null;
+ }
Preconditions.checkNotNull(who, "ComponentName is null");
enforceFullCrossUsersPermission(userHandle);
+ enforceCanManageProfileAndDeviceOwners();
synchronized (this) {
ActiveAdmin activeAdmin = getActiveAdminUncheckedLocked(who, userHandle);
if (activeAdmin == null) {
- throw new SecurityException("No active admin: " + activeAdmin);
- }
- if (activeAdmin.getUid() != mInjector.binderGetCallingUid()) {
- mContext.enforceCallingOrSelfPermission(
- android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS,
- "Calling uid " + mInjector.binderGetCallingUid() + " neither owns the admin"
- + " " + who + " nor has MANAGE_PROFILE_AND_DEVICE_OWNERS permission");
+ return null;
}
return activeAdmin.userRestrictions;
}
@@ -7820,9 +7919,9 @@
super(handler);
}
- void register(ContentResolver resolver) {
- resolver.registerContentObserver(mUserSetupComplete, false, this, UserHandle.USER_ALL);
- resolver.registerContentObserver(mDeviceProvisioned, false, this, UserHandle.USER_ALL);
+ void register() {
+ mInjector.registerContentObserver(mUserSetupComplete, false, this, UserHandle.USER_ALL);
+ mInjector.registerContentObserver(mDeviceProvisioned, false, this, UserHandle.USER_ALL);
}
@Override
@@ -8676,6 +8775,11 @@
null);
}
+ private void enforceCanManageProfileAndDeviceOwners() {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS, null);
+ }
+
@Override
public boolean isUninstallInQueue(final String packageName) {
enforceCanManageDeviceAdmin();
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 5975405..659450e 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -153,6 +153,10 @@
"com.android.server.MountService$Lifecycle";
private static final String SEARCH_MANAGER_SERVICE_CLASS =
"com.android.server.search.SearchManagerService$Lifecycle";
+ private static final String THERMAL_OBSERVER_CLASS =
+ "com.google.android.clockwork.ThermalObserver";
+ private static final String WEAR_BLUETOOTH_SERVICE_CLASS =
+ "com.google.android.clockwork.bluetooth.WearBluetoothService";
private static final String PERSISTENT_DATA_BLOCK_PROP = "ro.frp.pst";
@@ -165,7 +169,7 @@
* visual content.
*/
private static final int DEFAULT_SYSTEM_THEME =
- com.android.internal.R.style.Theme_Material_DayNight_DarkActionBar;
+ com.android.internal.R.style.Theme_Material_Light_DarkActionBar;
private final int mFactoryTestMode;
private Timer mProfilerSnapshotTimer;
@@ -695,6 +699,14 @@
// as appropriate.
mSystemServiceManager.startService(UiModeManagerService.class);
+ Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "UpdatePackagesIfNeeded");
+ try {
+ mPackageManagerService.updatePackagesIfNeeded();
+ } catch (Throwable e) {
+ reportWtf("update packages", e);
+ }
+ Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
+
Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "PerformFstrimIfNeeded");
try {
mPackageManagerService.performFstrimIfNeeded();
@@ -703,14 +715,6 @@
}
Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
- Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "ExtractPackagesIfNeeded");
- try {
- mPackageManagerService.extractPackagesIfNeeded();
- } catch (Throwable e) {
- reportWtf("extract packages", e);
- }
- Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
-
try {
ActivityManagerNative.getDefault().showBootMessage(
context.getResources().getText(
@@ -957,9 +961,8 @@
if (!disableNonCoreServices) {
mSystemServiceManager.startService(DockObserver.class);
- if (context.getPackageManager().hasSystemFeature
- (PackageManager.FEATURE_WATCH)) {
- mSystemServiceManager.startService(ThermalObserver.class);
+ if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH)) {
+ mSystemServiceManager.startService(THERMAL_OBSERVER_CLASS);
}
}
@@ -1023,7 +1026,8 @@
mSystemServiceManager.startService(BACKUP_MANAGER_SERVICE_CLASS);
}
- if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_APP_WIDGETS)) {
+ if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_APP_WIDGETS)
+ || context.getResources().getBoolean(R.bool.config_enableAppWidgetService)) {
mSystemServiceManager.startService(APPWIDGET_SERVICE_CLASS);
}
@@ -1129,7 +1133,9 @@
mSystemServiceManager.startService(TvInputManagerService.class);
}
- mSystemServiceManager.startService(MediaResourceMonitorService.class);
+ if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_PICTURE_IN_PICTURE)) {
+ mSystemServiceManager.startService(MediaResourceMonitorService.class);
+ }
if (!disableNonCoreServices) {
traceBeginAndSlog("StartMediaRouterService");
@@ -1167,6 +1173,10 @@
mSystemServiceManager.startService(MediaProjectionManagerService.class);
}
+ if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH)) {
+ mSystemServiceManager.startService(WEAR_BLUETOOTH_SERVICE_CLASS);
+ }
+
// Before things start rolling, be sure we have decided whether
// we are in safe mode.
final boolean safeMode = wm.detectSafeMode();
diff --git a/services/net/java/android/net/apf/ApfCapabilities.java b/services/net/java/android/net/apf/ApfCapabilities.java
index f169411..0ec50c4 100644
--- a/services/net/java/android/net/apf/ApfCapabilities.java
+++ b/services/net/java/android/net/apf/ApfCapabilities.java
@@ -43,4 +43,9 @@
this.maximumApfProgramSize = maximumApfProgramSize;
this.apfPacketFormat = apfPacketFormat;
}
-}
\ No newline at end of file
+
+ public String toString() {
+ return String.format("%s{version: %d, maxSize: %d format: %d}", getClass().getSimpleName(),
+ apfVersionSupported, maximumApfProgramSize, apfPacketFormat);
+ }
+}
diff --git a/services/net/java/android/net/apf/ApfFilter.java b/services/net/java/android/net/apf/ApfFilter.java
index ebbf991..f430a30 100644
--- a/services/net/java/android/net/apf/ApfFilter.java
+++ b/services/net/java/android/net/apf/ApfFilter.java
@@ -18,6 +18,7 @@
import static android.system.OsConstants.*;
+import android.net.LinkProperties;
import android.net.NetworkUtils;
import android.net.apf.ApfGenerator;
import android.net.apf.ApfGenerator.IllegalInstructionException;
@@ -136,6 +137,16 @@
// NOTE: this must be added to the IPv4 header length in IPV4_HEADER_SIZE_MEMORY_SLOT
private static final int DHCP_CLIENT_MAC_OFFSET = ETH_HEADER_LEN + UDP_HEADER_LEN + 28;
+ private static int ARP_HEADER_OFFSET = ETH_HEADER_LEN;
+ private static final byte[] ARP_IPV4_REQUEST_HEADER = new byte[]{
+ 0, 1, // Hardware type: Ethernet (1)
+ 8, 0, // Protocol type: IP (0x0800)
+ 6, // Hardware size: 6
+ 4, // Protocol size: 4
+ 0, 1 // Opcode: request (1)
+ };
+ private static int ARP_TARGET_IP_ADDRESS_OFFSET = ETH_HEADER_LEN + 24;
+
private final ApfCapabilities mApfCapabilities;
private final IpManager.Callback mIpManagerCallback;
private final NetworkInterface mNetworkInterface;
@@ -145,12 +156,16 @@
private long mUniqueCounter;
@GuardedBy("this")
private boolean mMulticastFilter;
+ // Our IPv4 address, if we have just one, otherwise null.
+ @GuardedBy("this")
+ private byte[] mIPv4Address;
private ApfFilter(ApfCapabilities apfCapabilities, NetworkInterface networkInterface,
- IpManager.Callback ipManagerCallback) {
+ IpManager.Callback ipManagerCallback, boolean multicastFilter) {
mApfCapabilities = apfCapabilities;
mIpManagerCallback = ipManagerCallback;
mNetworkInterface = networkInterface;
+ mMulticastFilter = multicastFilter;
maybeStartFilter();
}
@@ -225,6 +240,7 @@
private static final int ICMP6_4_BYTE_LIFETIME_OFFSET = 4;
private static final int ICMP6_4_BYTE_LIFETIME_LEN = 4;
+ // Note: mPacket's position() cannot be assumed to be reset.
private final ByteBuffer mPacket;
// List of binary ranges that include the whole packet except the lifetimes.
// Pairs consist of offset and length.
@@ -378,17 +394,12 @@
// Ignoring lifetimes (which may change) does {@code packet} match this RA?
boolean matches(byte[] packet, int length) {
- if (length != mPacket.limit()) return false;
- ByteBuffer a = ByteBuffer.wrap(packet);
- ByteBuffer b = mPacket;
+ if (length != mPacket.capacity()) return false;
+ byte[] referencePacket = mPacket.array();
for (Pair<Integer, Integer> nonLifetime : mNonLifetimes) {
- a.clear();
- b.clear();
- a.position(nonLifetime.first);
- b.position(nonLifetime.first);
- a.limit(nonLifetime.first + nonLifetime.second);
- b.limit(nonLifetime.first + nonLifetime.second);
- if (a.compareTo(b) != 0) return false;
+ for (int i = nonLifetime.first; i < (nonLifetime.first + nonLifetime.second); i++) {
+ if (packet[i] != referencePacket[i]) return false;
+ }
}
return true;
}
@@ -440,7 +451,7 @@
String nextFilterLabel = "Ra" + getUniqueNumberLocked();
// Skip if packet is not the right size
gen.addLoadFromMemory(Register.R0, gen.PACKET_SIZE_MEMORY_SLOT);
- gen.addJumpIfR0NotEquals(mPacket.limit(), nextFilterLabel);
+ gen.addJumpIfR0NotEquals(mPacket.capacity(), nextFilterLabel);
int filterLifetime = (int)(currentLifetime() / FRACTION_OF_LIFETIME_TO_FILTER);
// Skip filter if expired
gen.addLoadFromMemory(Register.R0, gen.FILTER_AGE_MEMORY_SLOT);
@@ -510,6 +521,33 @@
private byte[] mLastInstalledProgram;
/**
+ * Generate filter code to process ARP packets. Execution of this code ends in either the
+ * DROP_LABEL or PASS_LABEL and does not fall off the end.
+ * Preconditions:
+ * - Packet being filtered is ARP
+ */
+ @GuardedBy("this")
+ private void generateArpFilterLocked(ApfGenerator gen) throws IllegalInstructionException {
+ // Here's a basic summary of what the ARP filter program does:
+ //
+ // if it's not an ARP IPv4 request:
+ // pass
+ // if it's not a request for our IPv4 address:
+ // drop
+ // pass
+
+ // if it's not an ARP IPv4 request, pass
+ gen.addLoadImmediate(Register.R0, ARP_HEADER_OFFSET);
+ gen.addJumpIfBytesNotEqual(Register.R0, ARP_IPV4_REQUEST_HEADER, gen.PASS_LABEL);
+ // if it's not a request for our IPv4 address, drop
+ gen.addLoadImmediate(Register.R0, ARP_TARGET_IP_ADDRESS_OFFSET);
+ gen.addJumpIfBytesNotEqual(Register.R0, mIPv4Address, gen.DROP_LABEL);
+
+ // Otherwise, pass
+ gen.addJump(gen.PASS_LABEL);
+ }
+
+ /**
* Generate filter code to process IPv4 packets. Execution of this code ends in either the
* DROP_LABEL or PASS_LABEL and does not fall off the end.
* Preconditions:
@@ -566,7 +604,6 @@
* DROP_LABEL or PASS_LABEL, or falls off the end for ICMPv6 packets.
* Preconditions:
* - Packet being filtered is IPv6
- * - R1 is initialized to 0
*/
@GuardedBy("this")
private void generateIPv6FilterLocked(ApfGenerator gen) throws IllegalInstructionException {
@@ -598,6 +635,7 @@
/**
* Begin generating an APF program to:
* <ul>
+ * <li>Drop ARP requests not for us, if mIPv4Address is set,
* <li>Drop IPv4 broadcast packets, except DHCP destined to our MAC,
* <li>Drop IPv4 multicast packets, if mMulticastFilter,
* <li>Pass all other IPv4 packets,
@@ -616,16 +654,31 @@
// Here's a basic summary of what the initial program does:
//
+ // if it's ARP:
+ // inesrt ARP filter to drop or pass these appropriately
// if it's IPv4:
// insert IPv4 filter to drop or pass these appropriately
// if it's not IPv6:
// pass
// insert IPv6 filter to drop, pass, or fall off the end for ICMPv6 packets
+ gen.addLoad16(Register.R0, ETH_ETHERTYPE_OFFSET);
+
+ if (mIPv4Address != null) {
+ // Add ARP filters:
+ String skipArpFiltersLabel = "skipArpFilters";
+ // If not ARP, skip ARP filters
+ // NOTE: Relies on R0 containing ethertype.
+ gen.addJumpIfR0NotEquals(ETH_P_ARP, skipArpFiltersLabel);
+ generateArpFilterLocked(gen);
+ gen.defineLabel(skipArpFiltersLabel);
+ }
+
// Add IPv4 filters:
String skipIPv4FiltersLabel = "skipIPv4Filters";
- // If not IPv4, skip IPv4 filters
- gen.addLoad16(Register.R0, ETH_ETHERTYPE_OFFSET);
+ // NOTE: Relies on R0 containing ethertype. This is safe because if we got here, we did not
+ // execute the ARP filter, since that filter does not fall through, but either drops or
+ // passes.
gen.addJumpIfR0NotEquals(ETH_P_IP, skipIPv4FiltersLabel);
// NOTE: Relies on R1 being initialized to 0.
generateIPv4FilterLocked(gen);
@@ -634,8 +687,8 @@
// Add IPv6 filters:
// If not IPv6, pass
// NOTE: Relies on R0 containing ethertype. This is safe because if we got here, we did not
- // execute the IPv4 filter, since that filter does not fall through, but either drops or
- // passes.
+ // execute the ARP or IPv4 filters, since those filters do not fall through, but either
+ // drop or pass.
gen.addJumpIfR0NotEquals(ETH_P_IPV6, gen.PASS_LABEL);
generateIPv6FilterLocked(gen);
return gen;
@@ -752,7 +805,8 @@
* filtering using APF programs.
*/
public static ApfFilter maybeCreate(ApfCapabilities apfCapabilities,
- NetworkInterface networkInterface, IpManager.Callback ipManagerCallback) {
+ NetworkInterface networkInterface, IpManager.Callback ipManagerCallback,
+ boolean multicastFilter) {
if (apfCapabilities == null || networkInterface == null) return null;
if (apfCapabilities.apfVersionSupported == 0) return null;
if (apfCapabilities.maximumApfProgramSize < 512) {
@@ -768,7 +822,7 @@
Log.e(TAG, "Unsupported APF version: " + apfCapabilities.apfVersionSupported);
return null;
}
- return new ApfFilter(apfCapabilities, networkInterface, ipManagerCallback);
+ return new ApfFilter(apfCapabilities, networkInterface, ipManagerCallback, multicastFilter);
}
public synchronized void shutdown() {
@@ -787,10 +841,36 @@
}
}
+ // Find the single IPv4 address if there is one, otherwise return null.
+ private static byte[] findIPv4Address(LinkProperties lp) {
+ byte[] ipv4Address = null;
+ for (InetAddress inetAddr : lp.getAddresses()) {
+ byte[] addr = inetAddr.getAddress();
+ if (addr.length != 4) continue;
+ // More than one IPv4 address, abort
+ if (ipv4Address != null && !Arrays.equals(ipv4Address, addr)) return null;
+ ipv4Address = addr;
+ }
+ return ipv4Address;
+ }
+
+ public synchronized void setLinkProperties(LinkProperties lp) {
+ // NOTE: Do not keep a copy of LinkProperties as it would further duplicate state.
+ byte[] ipv4Address = findIPv4Address(lp);
+ // If ipv4Address is the same as mIPv4Address, then there's no change, just return.
+ if (Arrays.equals(ipv4Address, mIPv4Address)) return;
+ // Otherwise update mIPv4Address and install new program.
+ mIPv4Address = ipv4Address;
+ installNewProgramLocked();
+ }
+
public synchronized void dump(IndentingPrintWriter pw) {
- pw.println("APF version: " + mApfCapabilities.apfVersionSupported);
- pw.println("Max program size: " + mApfCapabilities.maximumApfProgramSize);
+ pw.println("APF caps: " + mApfCapabilities);
pw.println("Receive thread: " + (mReceiveThread != null ? "RUNNING" : "STOPPED"));
+ pw.println("Multicast filtering: " + mMulticastFilter);
+ try {
+ pw.println("IPv4 address: " + InetAddress.getByAddress(mIPv4Address));
+ } catch (UnknownHostException|NullPointerException e) {}
if (mLastTimeInstalledProgram == 0) {
pw.println("No program installed.");
return;
diff --git a/services/net/java/android/net/dhcp/DhcpPacket.java b/services/net/java/android/net/dhcp/DhcpPacket.java
index e27f69e..a881408 100644
--- a/services/net/java/android/net/dhcp/DhcpPacket.java
+++ b/services/net/java/android/net/dhcp/DhcpPacket.java
@@ -57,6 +57,17 @@
public static final int HWADDR_LEN = 16;
public static final int MAX_OPTION_LEN = 255;
+
+ /**
+ * The minimum and maximum MTU that we are prepared to use. We set the minimum to the minimum
+ * IPv6 MTU because the IPv6 stack enters unusual codepaths when the link MTU drops below 1280,
+ * and does not recover if the MTU is brought above 1280 again. We set the maximum to 1500
+ * because in general it is risky to assume that the hardware is able to send/receive packets
+ * larger than 1500 bytes even if the network supports it.
+ */
+ private static final int MIN_MTU = 1280;
+ private static final int MAX_MTU = 1500;
+
/**
* IP layer definitions.
*/
@@ -917,7 +928,7 @@
break;
case DHCP_MTU:
expectedLen = 2;
- mtu = Short.valueOf(packet.getShort());
+ mtu = packet.getShort();
break;
case DHCP_DOMAIN_NAME:
expectedLen = optionLen;
@@ -1106,6 +1117,8 @@
results.serverAddress = mServerIdentifier;
results.vendorInfo = mVendorInfo;
results.leaseDuration = (mLeaseTime != null) ? mLeaseTime : INFINITE_LEASE;
+ results.mtu = (mMtu != null && MIN_MTU <= mMtu && mMtu <= MAX_MTU) ? mMtu : 0;
+
return results;
}
diff --git a/services/net/java/android/net/ip/IpManager.java b/services/net/java/android/net/ip/IpManager.java
index 66c7909..54aeb3d 100644
--- a/services/net/java/android/net/ip/IpManager.java
+++ b/services/net/java/android/net/ip/IpManager.java
@@ -45,6 +45,7 @@
import com.android.internal.util.StateMachine;
import com.android.server.net.NetlinkTracker;
+import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.NetworkInterface;
@@ -99,10 +100,6 @@
public void onProvisioningSuccess(LinkProperties newLp) {}
public void onProvisioningFailure(LinkProperties newLp) {}
- // This is called whenever 464xlat is being enabled or disabled (i.e.
- // started or stopped).
- public void on464XlatChange(boolean enabled) {}
-
// Invoked on LinkProperties changes.
public void onLinkPropertiesChange(LinkProperties newLp) {}
@@ -115,6 +112,14 @@
// Install an APF program to filter incoming packets.
public void installPacketFilter(byte[] filter) {}
+
+ // If multicast filtering cannot be accomplished with APF, this function will be called to
+ // actuate multicast filtering using another means.
+ public void setFallbackMulticastFilter(boolean enabled) {}
+
+ // Enabled/disable Neighbor Discover offload functionality. This is
+ // called, for example, whenever 464xlat is being started or stopped.
+ public void setNeighborDiscoveryOffload(boolean enable) {}
}
public static class WaitForProvisioningCallback extends Callback {
@@ -211,6 +216,8 @@
}
}
+ public static final String DUMP_ARG = "ipmanager";
+
private static final int CMD_STOP = 1;
private static final int CMD_START = 2;
private static final int CMD_CONFIRM = 3;
@@ -219,6 +226,7 @@
private static final int EVENT_NETLINK_LINKPROPERTIES_CHANGED = 5;
private static final int CMD_UPDATE_TCP_BUFFER_SIZES = 6;
private static final int CMD_UPDATE_HTTP_PROXY = 7;
+ private static final int CMD_SET_MULTICAST_FILTER = 8;
private static final int MAX_LOG_RECORDS = 1000;
@@ -255,6 +263,7 @@
private String mTcpBufferSizes;
private ProxyInfo mHttpProxy;
private ApfFilter mApfFilter;
+ private boolean mMulticastFiltering;
/**
* Member variables accessed both from within the StateMachine thread
@@ -293,15 +302,20 @@
}) {
@Override
public void interfaceAdded(String iface) {
+ super.interfaceAdded(iface);
if (mClatInterfaceName.equals(iface)) {
- mCallback.on464XlatChange(true);
+ mCallback.setNeighborDiscoveryOffload(false);
}
}
@Override
public void interfaceRemoved(String iface) {
+ super.interfaceRemoved(iface);
if (mClatInterfaceName.equals(iface)) {
- mCallback.on464XlatChange(false);
+ // TODO: consider sending a message to the IpManager main
+ // StateMachine thread, in case "NDO enabled" state becomes
+ // tied to more things that 464xlat operation.
+ mCallback.setNeighborDiscoveryOffload(true);
}
}
};
@@ -387,23 +401,32 @@
sendMessage(CMD_UPDATE_HTTP_PROXY, proxyInfo);
}
+ /**
+ * Enable or disable the multicast filter. Attempts to use APF to accomplish the filtering,
+ * if not, Callback.setFallbackMulticastFilter() is called.
+ */
+ public void setMulticastFilter(boolean enabled) {
+ sendMessage(CMD_SET_MULTICAST_FILTER, enabled);
+ }
+
public LinkProperties getLinkProperties() {
synchronized (mLock) {
return new LinkProperties(mLinkProperties);
}
}
- public void dumpApf(PrintWriter writer) {
- writer.println("--------------------------------------------------------------------");
- writer.println("APF dump:");
+ public void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
+ IndentingPrintWriter pw = new IndentingPrintWriter(writer, " ");
+ pw.println("APF dump:");
+ pw.increaseIndent();
// Thread-unsafe access to mApfFilter but just used for debugging.
ApfFilter apfFilter = mApfFilter;
if (apfFilter != null) {
- apfFilter.dump(new IndentingPrintWriter(writer, " "));
+ apfFilter.dump(pw);
} else {
- writer.println("No apf support");
+ pw.println("No apf support");
}
- writer.println("--------------------------------------------------------------------");
+ pw.decreaseIndent();
}
@@ -515,6 +538,7 @@
}
private void dispatchCallback(ProvisioningChange delta, LinkProperties newLp) {
+ if (mApfFilter != null) mApfFilter.setLinkProperties(newLp);
switch (delta) {
case GAINED_PROVISIONING:
if (VDBG) { Log.d(mTag, "onProvisioningSuccess()"); }
@@ -601,6 +625,10 @@
}
}
newLp.setDomains(mDhcpResults.domains);
+
+ if (mDhcpResults.mtu != 0) {
+ newLp.setMtu(mDhcpResults.mtu);
+ }
}
// [4] Add in TCP buffer sizes and HTTP Proxy config, if available.
@@ -721,6 +749,10 @@
handleLinkPropertiesUpdate(NO_CALLBACKS);
break;
+ case CMD_SET_MULTICAST_FILTER:
+ mMulticastFiltering = (boolean) msg.obj;
+ break;
+
case DhcpClient.CMD_ON_QUIT:
// Everything is already stopped.
Log.e(mTag, "Unexpected CMD_ON_QUIT (already stopped).");
@@ -761,7 +793,10 @@
@Override
public void enter() {
mApfFilter = ApfFilter.maybeCreate(mConfiguration.mApfCapabilities, mNetworkInterface,
- mCallback);
+ mCallback, mMulticastFiltering);
+ // TODO: investigate the effects of any multicast filtering racing/interfering with the
+ // rest of this IP configuration startup.
+ if (mApfFilter == null) mCallback.setFallbackMulticastFilter(mMulticastFiltering);
// Set privacy extensions.
try {
mNwService.setInterfaceIpv6PrivacyExtensions(mInterfaceName, true);
@@ -874,6 +909,16 @@
handleLinkPropertiesUpdate(SEND_CALLBACKS);
break;
+ case CMD_SET_MULTICAST_FILTER: {
+ mMulticastFiltering = (boolean) msg.obj;
+ if (mApfFilter != null) {
+ mApfFilter.setMulticastFilter(mMulticastFiltering);
+ } else {
+ mCallback.setFallbackMulticastFilter(mMulticastFiltering);
+ }
+ break;
+ }
+
case DhcpClient.CMD_PRE_DHCP_ACTION:
if (VDBG) { Log.d(mTag, "onPreDhcpAction()"); }
if (mConfiguration.mRequestedPreDhcpAction) {
diff --git a/services/print/java/com/android/server/print/PrintManagerService.java b/services/print/java/com/android/server/print/PrintManagerService.java
index 985917b..4d02928 100644
--- a/services/print/java/com/android/server/print/PrintManagerService.java
+++ b/services/print/java/com/android/server/print/PrintManagerService.java
@@ -41,12 +41,14 @@
import android.print.IPrintDocumentAdapter;
import android.print.IPrintJobStateChangeListener;
import android.print.IPrintManager;
+import android.printservice.recommendation.IRecommendationsChangeListener;
import android.print.IPrintServicesChangeListener;
import android.print.IPrinterDiscoveryObserver;
import android.print.PrintAttributes;
import android.print.PrintJobId;
import android.print.PrintJobInfo;
import android.print.PrintManager;
+import android.printservice.recommendation.RecommendationInfo;
import android.print.PrinterId;
import android.printservice.PrintServiceInfo;
import android.provider.Settings;
@@ -265,7 +267,7 @@
final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
final UserState userState;
synchronized (mLock) {
- // Only the current group members can get enabled services.
+ // Only the current group members can get print services.
if (resolveCallingProfileParentLocked(resolvedUserId) != getCurrentUserId()) {
return null;
}
@@ -314,6 +316,25 @@
}
@Override
+ public List<RecommendationInfo> getPrintServiceRecommendations(int userId) {
+ final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
+ final UserState userState;
+ synchronized (mLock) {
+ // Only the current group members can get print service recommendations.
+ if (resolveCallingProfileParentLocked(resolvedUserId) != getCurrentUserId()) {
+ return null;
+ }
+ userState = getOrCreateUserStateLocked(resolvedUserId, false);
+ }
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ return userState.getPrintServiceRecommendations();
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
+ @Override
public void createPrinterDiscoverySession(IPrinterDiscoveryObserver observer,
int userId) {
observer = Preconditions.checkNotNull(observer);
@@ -543,7 +564,7 @@
final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
final UserState userState;
synchronized (mLock) {
- // Only the current group members can remove a print job listener.
+ // Only the current group members can remove a print services change listener.
if (resolveCallingProfileParentLocked(resolvedUserId) != getCurrentUserId()) {
return;
}
@@ -558,6 +579,52 @@
}
@Override
+ public void addPrintServiceRecommendationsChangeListener(
+ IRecommendationsChangeListener listener, int userId)
+ throws RemoteException {
+ listener = Preconditions.checkNotNull(listener);
+
+ final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
+ final UserState userState;
+ synchronized (mLock) {
+ // Only the current group members can add a print service recommendations listener.
+ if (resolveCallingProfileParentLocked(resolvedUserId) != getCurrentUserId()) {
+ return;
+ }
+ userState = getOrCreateUserStateLocked(resolvedUserId, false);
+ }
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ userState.addPrintServiceRecommendationsChangeListener(listener);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
+ @Override
+ public void removePrintServiceRecommendationsChangeListener(
+ IRecommendationsChangeListener listener, int userId) {
+ listener = Preconditions.checkNotNull(listener);
+
+ final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
+ final UserState userState;
+ synchronized (mLock) {
+ // Only the current group members can remove a print service recommendations
+ // listener.
+ if (resolveCallingProfileParentLocked(resolvedUserId) != getCurrentUserId()) {
+ return;
+ }
+ userState = getOrCreateUserStateLocked(resolvedUserId, false);
+ }
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ userState.removePrintServiceRecommendationsChangeListener(listener);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
+ @Override
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
fd = Preconditions.checkNotNull(fd);
pw = Preconditions.checkNotNull(pw);
diff --git a/services/print/java/com/android/server/print/RemotePrintServiceRecommendationService.java b/services/print/java/com/android/server/print/RemotePrintServiceRecommendationService.java
new file mode 100644
index 0000000..fa1f232
--- /dev/null
+++ b/services/print/java/com/android/server/print/RemotePrintServiceRecommendationService.java
@@ -0,0 +1,235 @@
+/*
+ * 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.print;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.ResolveInfo;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.printservice.recommendation.IRecommendationService;
+import android.printservice.recommendation.IRecommendationServiceCallbacks;
+import android.printservice.recommendation.RecommendationInfo;
+import android.util.Log;
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.util.Preconditions;
+
+import java.util.List;
+
+import static android.content.pm.PackageManager.GET_META_DATA;
+import static android.content.pm.PackageManager.GET_SERVICES;
+import static android.content.pm.PackageManager.MATCH_DEBUG_TRIAGED_MISSING;
+
+/**
+ * Connection to a remote print service recommendation service.
+ */
+class RemotePrintServiceRecommendationService {
+ private static final String LOG_TAG = "RemotePrintServiceRecS";
+
+ /** Lock for this object */
+ private final Object mLock = new Object();
+
+ /** Context used for the connection */
+ private @NonNull final Context mContext;
+
+ /** The connection to the service (if {@link #mIsBound bound}) */
+ @GuardedBy("mLock")
+ private @NonNull final Connection mConnection;
+
+ /** If the service is currently bound. */
+ @GuardedBy("mLock")
+ private boolean mIsBound;
+
+ /** The service once bound */
+ @GuardedBy("mLock")
+ private IRecommendationService mService;
+
+ /**
+ * Callbacks to be called when there are updates to the print service recommendations.
+ */
+ public interface RemotePrintServiceRecommendationServiceCallbacks {
+ /**
+ * Called when there is an update list of print service recommendations.
+ *
+ * @param recommendations The new recommendations.
+ */
+ void onPrintServiceRecommendationsUpdated(
+ @Nullable List<RecommendationInfo> recommendations);
+ }
+
+ /**
+ * @return The intent that is used to connect to the print service recommendation service.
+ */
+ private Intent getServiceIntent(@NonNull UserHandle userHandle) throws Exception {
+ List<ResolveInfo> installedServices = mContext.getPackageManager()
+ .queryIntentServicesAsUser(new Intent(
+ android.printservice.recommendation.RecommendationService.SERVICE_INTERFACE),
+ GET_SERVICES | GET_META_DATA | MATCH_DEBUG_TRIAGED_MISSING,
+ userHandle.getIdentifier());
+
+ if (installedServices.size() != 1) {
+ throw new Exception(installedServices.size() + " instead of exactly one service found");
+ }
+
+ ResolveInfo installedService = installedServices.get(0);
+
+ ComponentName serviceName = new ComponentName(
+ installedService.serviceInfo.packageName,
+ installedService.serviceInfo.name);
+
+ ApplicationInfo appInfo = mContext.getPackageManager()
+ .getApplicationInfo(installedService.serviceInfo.packageName, 0);
+
+ if (appInfo == null) {
+ throw new Exception("Cannot read appInfo for service");
+ }
+
+ if ((appInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
+ throw new Exception("Service is not part of the system");
+ }
+
+ if (!android.Manifest.permission.BIND_PRINT_RECOMMENDATION_SERVICE.equals(
+ installedService.serviceInfo.permission)) {
+ throw new Exception("Service " + serviceName.flattenToShortString()
+ + " does not require permission "
+ + android.Manifest.permission.BIND_PRINT_RECOMMENDATION_SERVICE);
+ }
+
+ Intent serviceIntent = new Intent();
+ serviceIntent.setComponent(serviceName);
+
+ return serviceIntent;
+ }
+
+ /**
+ * Open a new connection to a {@link IRecommendationService remote print service
+ * recommendation service}.
+ *
+ * @param context The context establishing the connection
+ * @param userHandle The user the connection is for
+ * @param callbacks The callbacks to call by the service
+ */
+ RemotePrintServiceRecommendationService(@NonNull Context context,
+ @NonNull UserHandle userHandle,
+ @NonNull RemotePrintServiceRecommendationServiceCallbacks callbacks) {
+ mContext = context;
+ mConnection = new Connection(callbacks);
+
+ try {
+ Intent serviceIntent = getServiceIntent(userHandle);
+
+ synchronized (mLock) {
+ mIsBound = mContext.bindServiceAsUser(serviceIntent, mConnection,
+ Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE, userHandle);
+
+ if (!mIsBound) {
+ throw new Exception("Failed to bind to service " + serviceIntent);
+ }
+ }
+ } catch (Exception e) {
+ Log.e(LOG_TAG, "Could not connect to print service recommendation service", e);
+ }
+ }
+
+ /**
+ * Terminate the connection to the {@link IRecommendationService remote print
+ * service recommendation service}.
+ */
+ void close() {
+ synchronized (mLock) {
+ if (mService != null) {
+ try {
+ mService.registerCallbacks(null);
+ } catch (RemoteException e) {
+ Log.e(LOG_TAG, "Could not unregister callbacks", e);
+ }
+
+ mService = null;
+ }
+
+ if (mIsBound) {
+ mContext.unbindService(mConnection);
+ mIsBound = false;
+ }
+ }
+ }
+
+ @Override
+ protected void finalize() throws Throwable {
+ if (mIsBound || mService != null) {
+ Log.w(LOG_TAG, "Service still connected on finalize()");
+ close();
+ }
+
+ super.finalize();
+ }
+
+ /**
+ * Connection to the service.
+ */
+ private class Connection implements ServiceConnection {
+ private final RemotePrintServiceRecommendationServiceCallbacks mCallbacks;
+
+ public Connection(@NonNull RemotePrintServiceRecommendationServiceCallbacks callbacks) {
+ mCallbacks = callbacks;
+ }
+
+ @Override
+ public void onServiceConnected(ComponentName name, IBinder service) {
+ synchronized (mLock) {
+ mService = (IRecommendationService)IRecommendationService.Stub.asInterface(service);
+
+ try {
+ mService.registerCallbacks(new IRecommendationServiceCallbacks.Stub() {
+ @Override
+ public void onRecommendationsUpdated(
+ List<RecommendationInfo> recommendations) {
+ synchronized (mLock) {
+ if (mIsBound && mService != null) {
+ if (recommendations != null) {
+ Preconditions.checkCollectionElementsNotNull(
+ recommendations, "recommendation");
+ }
+
+ mCallbacks.onPrintServiceRecommendationsUpdated(
+ recommendations);
+ }
+ }
+ }
+ });
+ } catch (RemoteException e) {
+ Log.e(LOG_TAG, "Could not register callbacks", e);
+ }
+ }
+ }
+
+ @Override
+ public void onServiceDisconnected(ComponentName name) {
+ Log.w(LOG_TAG, "Unexpected termination of connection");
+
+ synchronized (mLock) {
+ mService = null;
+ }
+ }
+ }
+}
diff --git a/services/print/java/com/android/server/print/UserState.java b/services/print/java/com/android/server/print/UserState.java
index 263dead..026942e 100644
--- a/services/print/java/com/android/server/print/UserState.java
+++ b/services/print/java/com/android/server/print/UserState.java
@@ -37,6 +37,7 @@
import android.os.Handler;
import android.os.IBinder;
import android.os.IBinder.DeathRecipient;
+import android.os.IInterface;
import android.os.Looper;
import android.os.Message;
import android.os.RemoteCallbackList;
@@ -44,12 +45,14 @@
import android.os.UserHandle;
import android.print.IPrintDocumentAdapter;
import android.print.IPrintJobStateChangeListener;
+import android.printservice.recommendation.IRecommendationsChangeListener;
import android.print.IPrintServicesChangeListener;
import android.print.IPrinterDiscoveryObserver;
import android.print.PrintAttributes;
import android.print.PrintJobId;
import android.print.PrintJobInfo;
import android.print.PrintManager;
+import android.printservice.recommendation.RecommendationInfo;
import android.print.PrinterId;
import android.print.PrinterInfo;
import android.printservice.PrintServiceInfo;
@@ -68,6 +71,7 @@
import com.android.internal.os.SomeArgs;
import com.android.server.print.RemotePrintService.PrintServiceCallbacks;
import com.android.server.print.RemotePrintSpooler.PrintSpoolerCallbacks;
+import com.android.server.print.RemotePrintServiceRecommendationService.RemotePrintServiceRecommendationServiceCallbacks;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -82,7 +86,8 @@
/**
* Represents the print state for a user.
*/
-final class UserState implements PrintSpoolerCallbacks, PrintServiceCallbacks {
+final class UserState implements PrintSpoolerCallbacks, PrintServiceCallbacks,
+ RemotePrintServiceRecommendationServiceCallbacks {
private static final String LOG_TAG = "UserState";
@@ -122,10 +127,22 @@
private List<PrintJobStateChangeListenerRecord> mPrintJobStateChangeListenerRecords;
- private List<PrintServicesChangeListenerRecord> mPrintServicesChangeListenerRecords;
+ private List<ListenerRecord<IPrintServicesChangeListener>> mPrintServicesChangeListenerRecords;
+
+ private List<ListenerRecord<IRecommendationsChangeListener>>
+ mPrintServiceRecommendationsChangeListenerRecords;
private boolean mDestroyed;
+ /** Currently known list of print service recommendations */
+ private List<RecommendationInfo> mPrintServiceRecommendations;
+
+ /**
+ * Connection to the service updating the {@link #mPrintServiceRecommendations print service
+ * recommendations}.
+ */
+ private RemotePrintServiceRecommendationService mPrintServiceRecommendationsService;
+
public UserState(Context context, int userId, Object lock, boolean lowPriority) {
mContext = context;
mUserId = userId;
@@ -409,6 +426,13 @@
}
}
+ /**
+ * @return The currently known print service recommendations
+ */
+ public @Nullable List<RecommendationInfo> getPrintServiceRecommendations() {
+ return mPrintServiceRecommendations;
+ }
+
public void createPrinterDiscoverySession(@NonNull IPrinterDiscoveryObserver observer) {
synchronized (mLock) {
throwIfDestroyedLocked();
@@ -566,7 +590,7 @@
mPrintServicesChangeListenerRecords = new ArrayList<>();
}
mPrintServicesChangeListenerRecords.add(
- new PrintServicesChangeListenerRecord(listener) {
+ new ListenerRecord<IPrintServicesChangeListener>(listener) {
@Override
public void onBinderDied() {
mPrintServicesChangeListenerRecords.remove(this);
@@ -583,7 +607,7 @@
}
final int recordCount = mPrintServicesChangeListenerRecords.size();
for (int i = 0; i < recordCount; i++) {
- PrintServicesChangeListenerRecord record =
+ ListenerRecord<IPrintServicesChangeListener> record =
mPrintServicesChangeListenerRecords.get(i);
if (record.listener.asBinder().equals(listener.asBinder())) {
mPrintServicesChangeListenerRecords.remove(i);
@@ -596,6 +620,54 @@
}
}
+ public void addPrintServiceRecommendationsChangeListener(
+ @NonNull IRecommendationsChangeListener listener) throws RemoteException {
+ synchronized (mLock) {
+ throwIfDestroyedLocked();
+ if (mPrintServiceRecommendationsChangeListenerRecords == null) {
+ mPrintServiceRecommendationsChangeListenerRecords = new ArrayList<>();
+
+ mPrintServiceRecommendationsService =
+ new RemotePrintServiceRecommendationService(mContext,
+ UserHandle.getUserHandleForUid(mUserId), this);
+ }
+ mPrintServiceRecommendationsChangeListenerRecords.add(
+ new ListenerRecord<IRecommendationsChangeListener>(listener) {
+ @Override
+ public void onBinderDied() {
+ mPrintServiceRecommendationsChangeListenerRecords.remove(this);
+ }
+ });
+ }
+ }
+
+ public void removePrintServiceRecommendationsChangeListener(
+ @NonNull IRecommendationsChangeListener listener) {
+ synchronized (mLock) {
+ throwIfDestroyedLocked();
+ if (mPrintServiceRecommendationsChangeListenerRecords == null) {
+ return;
+ }
+ final int recordCount = mPrintServiceRecommendationsChangeListenerRecords.size();
+ for (int i = 0; i < recordCount; i++) {
+ ListenerRecord<IRecommendationsChangeListener> record =
+ mPrintServiceRecommendationsChangeListenerRecords.get(i);
+ if (record.listener.asBinder().equals(listener.asBinder())) {
+ mPrintServiceRecommendationsChangeListenerRecords.remove(i);
+ break;
+ }
+ }
+ if (mPrintServiceRecommendationsChangeListenerRecords.isEmpty()) {
+ mPrintServiceRecommendationsChangeListenerRecords = null;
+
+ mPrintServiceRecommendations = null;
+
+ mPrintServiceRecommendationsService.close();
+ mPrintServiceRecommendationsService = null;
+ }
+ }
+ }
+
@Override
public void onPrintJobStateChanged(PrintJobInfo printJob) {
mPrintJobForAppCache.onPrintJobStateChanged(printJob);
@@ -608,6 +680,12 @@
}
@Override
+ public void onPrintServiceRecommendationsUpdated(List<RecommendationInfo> recommendations) {
+ mHandler.obtainMessage(UserStateHandler.MSG_DISPATCH_PRINT_SERVICES_RECOMMENDATIONS_UPDATED,
+ 0, 0, recommendations).sendToTarget();
+ }
+
+ @Override
public void onPrintersAdded(List<PrinterInfo> printers) {
synchronized (mLock) {
throwIfDestroyedLocked();
@@ -1058,7 +1136,7 @@
}
private void handleDispatchPrintServicesChanged() {
- final List<PrintServicesChangeListenerRecord> records;
+ final List<ListenerRecord<IPrintServicesChangeListener>> records;
synchronized (mLock) {
if (mPrintServicesChangeListenerRecords == null) {
return;
@@ -1067,7 +1145,7 @@
}
final int recordCount = records.size();
for (int i = 0; i < recordCount; i++) {
- PrintServicesChangeListenerRecord record = records.get(i);
+ ListenerRecord<IPrintServicesChangeListener> record = records.get(i);
try {
record.listener.onPrintServicesChanged();;
@@ -1077,9 +1155,33 @@
}
}
+ private void handleDispatchPrintServiceRecommendationsUpdated(
+ @Nullable List<RecommendationInfo> recommendations) {
+ final List<ListenerRecord<IRecommendationsChangeListener>> records;
+ synchronized (mLock) {
+ if (mPrintServiceRecommendationsChangeListenerRecords == null) {
+ return;
+ }
+ records = new ArrayList<>(mPrintServiceRecommendationsChangeListenerRecords);
+
+ mPrintServiceRecommendations = recommendations;
+ }
+ final int recordCount = records.size();
+ for (int i = 0; i < recordCount; i++) {
+ ListenerRecord<IRecommendationsChangeListener> record = records.get(i);
+
+ try {
+ record.listener.onRecommendationsChanged();
+ } catch (RemoteException re) {
+ Log.e(LOG_TAG, "Error notifying for print service recommendations change", re);
+ }
+ }
+ }
+
private final class UserStateHandler extends Handler {
public static final int MSG_DISPATCH_PRINT_JOB_STATE_CHANGED = 1;
public static final int MSG_DISPATCH_PRINT_SERVICES_CHANGED = 2;
+ public static final int MSG_DISPATCH_PRINT_SERVICES_RECOMMENDATIONS_UPDATED = 3;
public UserStateHandler(Looper looper) {
super(looper, null, false);
@@ -1096,6 +1198,10 @@
case MSG_DISPATCH_PRINT_SERVICES_CHANGED:
handleDispatchPrintServicesChanged();
break;
+ case MSG_DISPATCH_PRINT_SERVICES_RECOMMENDATIONS_UPDATED:
+ handleDispatchPrintServiceRecommendationsUpdated(
+ (List<RecommendationInfo>) message.obj);
+ break;
default:
// not reached
}
@@ -1122,10 +1228,10 @@
public abstract void onBinderDied();
}
- private abstract class PrintServicesChangeListenerRecord implements DeathRecipient {
- @NonNull final IPrintServicesChangeListener listener;
+ private abstract class ListenerRecord<T extends IInterface> implements DeathRecipient {
+ @NonNull final T listener;
- public PrintServicesChangeListenerRecord(@NonNull IPrintServicesChangeListener listener) throws RemoteException {
+ public ListenerRecord(@NonNull T listener) throws RemoteException {
this.listener = listener;
listener.asBinder().linkToDeath(this, 0);
}
diff --git a/services/tests/servicestests/src/android/net/dhcp/DhcpPacketTest.java b/services/tests/servicestests/src/android/net/dhcp/DhcpPacketTest.java
index 876d95b..f8eaf7d 100644
--- a/services/tests/servicestests/src/android/net/dhcp/DhcpPacketTest.java
+++ b/services/tests/servicestests/src/android/net/dhcp/DhcpPacketTest.java
@@ -261,7 +261,7 @@
private void assertDhcpResults(String ipAddress, String gateway, String dnsServersString,
String domains, String serverAddress, String vendorInfo, int leaseDuration,
- boolean hasMeteredHint, DhcpResults dhcpResults) throws Exception {
+ boolean hasMeteredHint, int mtu, DhcpResults dhcpResults) throws Exception {
assertEquals(new LinkAddress(ipAddress), dhcpResults.ipAddress);
assertEquals(v4Address(gateway), dhcpResults.gateway);
@@ -277,6 +277,7 @@
assertEquals(vendorInfo, dhcpResults.vendorInfo);
assertEquals(leaseDuration, dhcpResults.leaseDuration);
assertEquals(hasMeteredHint, dhcpResults.hasMeteredHint());
+ assertEquals(mtu, dhcpResults.mtu);
}
@SmallTest
@@ -310,7 +311,7 @@
assertTrue(offerPacket instanceof DhcpOfferPacket); // Implicitly checks it's non-null.
DhcpResults dhcpResults = offerPacket.toDhcpResults();
assertDhcpResults("192.168.159.247/20", "192.168.159.254", "8.8.8.8,8.8.4.4",
- null, "192.168.144.3", null, 7200, false, dhcpResults);
+ null, "192.168.144.3", null, 7200, false, 0, dhcpResults);
}
@SmallTest
@@ -342,10 +343,70 @@
assertTrue(offerPacket instanceof DhcpOfferPacket); // Implicitly checks it's non-null.
DhcpResults dhcpResults = offerPacket.toDhcpResults();
assertDhcpResults("192.168.43.247/24", "192.168.43.1", "192.168.43.1",
- null, "192.168.43.1", "ANDROID_METERED", 3600, true, dhcpResults);
+ null, "192.168.43.1", "ANDROID_METERED", 3600, true, 0, dhcpResults);
assertTrue(dhcpResults.hasMeteredHint());
}
+ private byte[] mtuBytes(int mtu) {
+ // 0x1a02: option 26, length 2. 0xff: no more options.
+ if (mtu > Short.MAX_VALUE - Short.MIN_VALUE) {
+ throw new IllegalArgumentException(
+ String.format("Invalid MTU %d, must be 16-bit unsigned", mtu));
+ }
+ String hexString = String.format("1a02%04xff", mtu);
+ return HexEncoding.decode(hexString.toCharArray(), false);
+ }
+
+ private void checkMtu(ByteBuffer packet, int expectedMtu, byte[] mtuBytes) throws Exception {
+ if (mtuBytes != null) {
+ packet.position(packet.capacity() - mtuBytes.length);
+ packet.put(mtuBytes);
+ packet.clear();
+ }
+ DhcpPacket offerPacket = DhcpPacket.decodeFullPacket(packet, ENCAP_L3);
+ assertTrue(offerPacket instanceof DhcpOfferPacket); // Implicitly checks it's non-null.
+ DhcpResults dhcpResults = offerPacket.toDhcpResults();
+ assertDhcpResults("192.168.159.247/20", "192.168.159.254", "8.8.8.8,8.8.4.4",
+ null, "192.168.144.3", null, 7200, false, expectedMtu, dhcpResults);
+ }
+
+ @SmallTest
+ public void testMtu() throws Exception {
+ final ByteBuffer packet = ByteBuffer.wrap(HexEncoding.decode((
+ // IP header.
+ "451001480000000080118849c0a89003c0a89ff7" +
+ // UDP header.
+ "004300440134dcfa" +
+ // BOOTP header.
+ "02010600c997a63b0000000000000000c0a89ff70000000000000000" +
+ // MAC address.
+ "30766ff2a90c00000000000000000000" +
+ // Server name.
+ "0000000000000000000000000000000000000000000000000000000000000000" +
+ "0000000000000000000000000000000000000000000000000000000000000000" +
+ // File.
+ "0000000000000000000000000000000000000000000000000000000000000000" +
+ "0000000000000000000000000000000000000000000000000000000000000000" +
+ "0000000000000000000000000000000000000000000000000000000000000000" +
+ "0000000000000000000000000000000000000000000000000000000000000000" +
+ // Options
+ "638253633501023604c0a89003330400001c200104fffff0000304c0a89ffe06080808080808080404" +
+ "3a0400000e103b040000189cff00000000"
+ ).toCharArray(), false));
+
+ checkMtu(packet, 0, null);
+ checkMtu(packet, 0, mtuBytes(1501));
+ checkMtu(packet, 1500, mtuBytes(1500));
+ checkMtu(packet, 1499, mtuBytes(1499));
+ checkMtu(packet, 1280, mtuBytes(1280));
+ checkMtu(packet, 0, mtuBytes(1279));
+ checkMtu(packet, 0, mtuBytes(576));
+ checkMtu(packet, 0, mtuBytes(68));
+ checkMtu(packet, 0, mtuBytes(Short.MIN_VALUE));
+ checkMtu(packet, 0, mtuBytes(Short.MAX_VALUE + 3));
+ checkMtu(packet, 0, mtuBytes(-1));
+ }
+
@SmallTest
public void testBadHwaddrLength() throws Exception {
final ByteBuffer packet = ByteBuffer.wrap(HexEncoding.decode((
@@ -453,7 +514,7 @@
assertTrue(offerPacket instanceof DhcpOfferPacket);
DhcpResults dhcpResults = offerPacket.toDhcpResults();
assertDhcpResults("172.17.152.118/16", "172.17.1.1", "172.17.1.1",
- null, "1.1.1.1", null, 43200, false, dhcpResults);
+ null, "1.1.1.1", null, 43200, false, 0, dhcpResults);
}
@SmallTest
@@ -484,7 +545,7 @@
assertTrue(offerPacket instanceof DhcpOfferPacket);
DhcpResults dhcpResults = offerPacket.toDhcpResults();
assertDhcpResults("10.63.93.4/20", "10.63.80.1", "192.0.2.1,192.0.2.2",
- "domain123.co.uk", "192.0.2.254", null, 49094, false, dhcpResults);
+ "domain123.co.uk", "192.0.2.254", null, 49094, false, 0, dhcpResults);
}
@SmallTest
@@ -518,7 +579,7 @@
assertEquals("BCF5AC000000", HexDump.toHexString(offerPacket.getClientMac()));
DhcpResults dhcpResults = offerPacket.toDhcpResults();
assertDhcpResults("10.32.158.205/20", "10.32.144.1", "148.88.65.52,148.88.65.53",
- "lancs.ac.uk", "10.32.255.128", null, 7200, false, dhcpResults);
+ "lancs.ac.uk", "10.32.255.128", null, 7200, false, 0, dhcpResults);
}
@SmallTest
@@ -554,7 +615,7 @@
DhcpResults dhcpResults = offerPacket.toDhcpResults();
assertDhcpResults("10.15.122.242/16", "10.15.200.23",
"209.129.128.3,209.129.148.3,209.129.128.6",
- "wvm.edu", "10.1.105.252", null, 86400, false, dhcpResults);
+ "wvm.edu", "10.1.105.252", null, 86400, false, 0, dhcpResults);
}
@SmallTest
@@ -621,7 +682,7 @@
assertEquals("FC3D93000000", HexDump.toHexString(offerPacket.getClientMac()));
DhcpResults dhcpResults = offerPacket.toDhcpResults();
assertDhcpResults("192.168.189.49/24", "192.168.189.1", "8.8.8.8,8.8.4.4",
- null, "192.171.189.2", null, 28800, false, dhcpResults);
+ null, "192.171.189.2", null, 28800, false, 0, dhcpResults);
}
@SmallTest
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java
index 35777ce..744443f 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java
@@ -15,14 +15,14 @@
*/
package com.android.server.devicepolicy;
-import com.android.internal.widget.LockPatternUtils;
-
import android.app.IActivityManager;
import android.app.NotificationManager;
import android.app.backup.IBackupManager;
import android.content.pm.IPackageManager;
import android.content.pm.PackageManagerInternal;
+import android.database.ContentObserver;
import android.media.IAudioService;
+import android.net.Uri;
import android.os.Looper;
import android.os.PowerManagerInternal;
import android.os.UserHandle;
@@ -30,12 +30,15 @@
import android.os.UserManagerInternal;
import android.os.storage.StorageManager;
import android.telephony.TelephonyManager;
+import android.util.ArrayMap;
+import android.util.Log;
+import android.util.Pair;
import android.view.IWindowManager;
-import java.io.File;
+import com.android.internal.widget.LockPatternUtils;
-import static org.mockito.Matchers.eq;
-import static org.mockito.Mockito.when;
+import java.io.File;
+import java.util.Map;
/**
* Overrides {@link #DevicePolicyManagerService} for dependency injection.
@@ -77,6 +80,7 @@
}
public final DpmMockContext context;
+ private final MockInjector mMockInjector;
public DevicePolicyManagerServiceTestable(DpmMockContext context, File dataDir) {
this(new MockInjector(context, dataDir));
@@ -84,15 +88,36 @@
private DevicePolicyManagerServiceTestable(MockInjector injector) {
super(injector);
+ mMockInjector = injector;
this.context = injector.context;
}
+
+ public void notifyChangeToContentObserver(Uri uri, int userHandle) {
+ ContentObserver co = mMockInjector.mContentObservers
+ .get(new Pair<Uri, Integer>(uri, userHandle));
+ if (co != null) {
+ co.onChange(false, uri, userHandle); // notify synchronously
+ }
+
+ // Notify USER_ALL observer too.
+ co = mMockInjector.mContentObservers
+ .get(new Pair<Uri, Integer>(uri, UserHandle.USER_ALL));
+ if (co != null) {
+ co.onChange(false, uri, userHandle); // notify synchronously
+ }
+ }
+
+
private static class MockInjector extends Injector {
public final DpmMockContext context;
public final File dataDir;
+ // Key is a pair of uri and userId
+ private final Map<Pair<Uri, Integer>, ContentObserver> mContentObservers = new ArrayMap<>();
+
private MockInjector(DpmMockContext context, File dataDir) {
super(context);
this.context = context;
@@ -265,6 +290,12 @@
}
@Override
+ void registerContentObserver(Uri uri, boolean notifyForDescendents,
+ ContentObserver observer, int userHandle) {
+ mContentObservers.put(new Pair<Uri, Integer>(uri, userHandle), observer);
+ }
+
+ @Override
int settingsSecureGetIntForUser(String name, int def, int userHandle) {
return context.settings.settingsSecureGetIntForUser(name, def, userHandle);
}
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
index e6963d5..3a2e946 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -543,10 +543,31 @@
}
/**
- * Test for: {@link DevicePolicyManager#setDeviceOwner} DO on system user installs
- * successfully.
+ * Test for: {@link DevicePolicyManager#setDeviceOwner} DO on system user installs successfully.
*/
public void testSetDeviceOwner() throws Exception {
+ setDeviceOwner();
+
+ // Try to set a profile owner on the same user, which should fail.
+ setUpPackageManagerForAdmin(admin2, DpmMockContext.CALLER_SYSTEM_USER_UID);
+ dpm.setActiveAdmin(admin2, /* refreshing= */ true, UserHandle.USER_SYSTEM);
+ try {
+ dpm.setProfileOwner(admin2, "owner-name", UserHandle.USER_SYSTEM);
+ fail("IllegalStateException not thrown");
+ } catch (IllegalStateException expected) {
+ assertTrue("Message was: " + expected.getMessage(),
+ expected.getMessage().contains("already has a device owner"));
+ }
+
+ // DO admin can't be deactivated.
+ dpm.removeActiveAdmin(admin1);
+ assertTrue(dpm.isAdminActive(admin1));
+
+ // TODO Test getDeviceOwnerName() too. To do so, we need to change
+ // DPMS.getApplicationLabel() because Context.createPackageContextAsUser() is not mockable.
+ }
+
+ private void setDeviceOwner() throws Exception {
mContext.callerPermissions.add(permission.MANAGE_DEVICE_ADMINS);
mContext.callerPermissions.add(permission.MANAGE_USERS);
mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
@@ -594,24 +615,6 @@
MockUtils.checkUserHandle(UserHandle.USER_SYSTEM));
assertEquals(admin1, dpm.getDeviceOwnerComponentOnAnyUser());
-
- // Try to set a profile owner on the same user, which should fail.
- setUpPackageManagerForAdmin(admin2, DpmMockContext.CALLER_SYSTEM_USER_UID);
- dpm.setActiveAdmin(admin2, /* refreshing= */ true, UserHandle.USER_SYSTEM);
- try {
- dpm.setProfileOwner(admin2, "owner-name", UserHandle.USER_SYSTEM);
- fail("IllegalStateException not thrown");
- } catch (IllegalStateException expected) {
- assertTrue("Message was: " + expected.getMessage(),
- expected.getMessage().contains("already has a device owner"));
- }
-
- // DO admin can't be deactivated.
- dpm.removeActiveAdmin(admin1);
- assertTrue(dpm.isAdminActive(admin1));
-
- // TODO Test getDeviceOwnerName() too. To do so, we need to change
- // DPMS.getApplicationLabel() because Context.createPackageContextAsUser() is not mockable.
}
private void checkGetDeviceOwnerInfoApi(DevicePolicyManager dpm, boolean hasDeviceOwner) {
@@ -1934,5 +1937,211 @@
// TODO Verify calls to settingsGlobalPutInt. Tried but somehow mockito threw
// UnfinishedVerificationException.
}
-}
+ public void testIsProvisioningAllowed_DeviceAdminFeatureOff() throws Exception {
+ when(mContext.packageManager.hasSystemFeature(PackageManager.FEATURE_DEVICE_ADMIN))
+ .thenReturn(false);
+ when(mContext.ipackageManager.hasSystemFeature(PackageManager.FEATURE_MANAGED_USERS, 0))
+ .thenReturn(false);
+ initializeDpms();
+ when(mContext.userManagerForMock.isSplitSystemUser()).thenReturn(false);
+ when(mContext.userManager.canAddMoreManagedProfiles(UserHandle.USER_SYSTEM, true))
+ .thenReturn(true);
+ setUserSetupCompleteForUser(false, UserHandle.USER_SYSTEM);
+
+ mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
+
+ assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE, false);
+ assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, false);
+ assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE,
+ false);
+ assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_USER, false);
+ }
+
+ public void testIsProvisioningAllowed_ManagedProfileFeatureOff() throws Exception {
+ when(mContext.ipackageManager.hasSystemFeature(PackageManager.FEATURE_MANAGED_USERS, 0))
+ .thenReturn(false);
+ initializeDpms();
+ when(mContext.userManagerForMock.isSplitSystemUser()).thenReturn(false);
+ when(mContext.userManager.canAddMoreManagedProfiles(UserHandle.USER_SYSTEM, true))
+ .thenReturn(true);
+ setUserSetupCompleteForUser(false, UserHandle.USER_SYSTEM);
+
+ mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
+
+ assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE, true);
+ assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, false);
+ assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE,
+ false);
+ assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_USER, false);
+
+ // Test again when split user is on
+ when(mContext.userManagerForMock.isSplitSystemUser()).thenReturn(true);
+ assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE, true);
+ assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, false);
+ assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE,
+ true);
+ assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_USER, false);
+ }
+
+ public void testIsProvisioningAllowed_nonSplitUser_firstBoot_primaryUser() throws Exception {
+ when(mContext.ipackageManager.hasSystemFeature(PackageManager.FEATURE_MANAGED_USERS, 0))
+ .thenReturn(true);
+ when(mContext.userManagerForMock.isSplitSystemUser()).thenReturn(false);
+ when(mContext.userManager.canAddMoreManagedProfiles(UserHandle.USER_SYSTEM, true))
+ .thenReturn(true);
+ setUserSetupCompleteForUser(false, UserHandle.USER_SYSTEM);
+
+ mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
+
+ assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE, true);
+ assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, true);
+ assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE,
+ false /* because of non-split user */);
+ assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_USER,
+ false /* because of non-split user */);
+ }
+
+ public void testIsProvisioningAllowed_nonSplitUser_afterDeviceSetup_primaryUser()
+ throws Exception {
+ when(mContext.ipackageManager.hasSystemFeature(PackageManager.FEATURE_MANAGED_USERS, 0))
+ .thenReturn(true);
+ when(mContext.userManagerForMock.isSplitSystemUser()).thenReturn(false);
+ when(mContext.userManager.canAddMoreManagedProfiles(UserHandle.USER_SYSTEM, true))
+ .thenReturn(true);
+ setUserSetupCompleteForUser(true, UserHandle.USER_SYSTEM);
+
+ mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
+
+ assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE,
+ false/* because of completed device setup */);
+ assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, true);
+ assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE,
+ false/* because of non-split user */);
+ assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_USER,
+ false/* because of non-split user */);
+ }
+
+ public void testIsProvisioningAllowed_splitUser_firstBoot_systemUser() throws Exception {
+ when(mContext.ipackageManager.hasSystemFeature(PackageManager.FEATURE_MANAGED_USERS, 0))
+ .thenReturn(true);
+ when(mContext.userManagerForMock.isSplitSystemUser()).thenReturn(true);
+ when(mContext.userManager.canAddMoreManagedProfiles(UserHandle.USER_SYSTEM, true))
+ .thenReturn(false);
+ setUserSetupCompleteForUser(false, UserHandle.USER_SYSTEM);
+
+ mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
+
+ assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE, true);
+ assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE,
+ false /* because canAddMoreManagedProfiles returns false */);
+ assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE,
+ true);
+ assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_USER,
+ false/* because calling uid is system user */);
+
+ }
+
+ public void testIsProvisioningAllowed_splitUser_afterDeviceSetup_systemUser() throws Exception {
+ when(mContext.ipackageManager.hasSystemFeature(PackageManager.FEATURE_MANAGED_USERS, 0))
+ .thenReturn(true);
+ when(mContext.userManagerForMock.isSplitSystemUser()).thenReturn(true);
+ when(mContext.userManager.canAddMoreManagedProfiles(UserHandle.USER_SYSTEM, true))
+ .thenReturn(false);
+ setUserSetupCompleteForUser(true, UserHandle.USER_SYSTEM);
+
+ mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
+
+ assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE,
+ true/* it's undefined behavior. Can be changed into false in the future */);
+ assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE,
+ false /* because canAddMoreManagedProfiles returns false */);
+ assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE,
+ true/* it's undefined behavior. Can be changed into false in the future */);
+ assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_USER,
+ false/* because calling uid is system user */);
+ }
+
+ public void testIsProvisioningAllowed_splitUser_firstBoot_primaryUser() throws Exception {
+ when(mContext.ipackageManager.hasSystemFeature(PackageManager.FEATURE_MANAGED_USERS, 0))
+ .thenReturn(true);
+ when(mContext.userManagerForMock.isSplitSystemUser()).thenReturn(true);
+ when(mContext.userManager.canAddMoreManagedProfiles(DpmMockContext.CALLER_USER_HANDLE,
+ true)).thenReturn(true);
+ setUserSetupCompleteForUser(false, DpmMockContext.CALLER_USER_HANDLE);
+
+ mContext.binder.callingUid = DpmMockContext.CALLER_UID;
+
+ assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE, true);
+ assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, true);
+ assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE,
+ true);
+ assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_USER, true);
+
+ }
+
+ public void testIsProvisioningAllowed_splitUser_afterDeviceSetup_primaryUser()
+ throws Exception {
+ when(mContext.ipackageManager.hasSystemFeature(PackageManager.FEATURE_MANAGED_USERS, 0))
+ .thenReturn(true);
+ when(mContext.userManagerForMock.isSplitSystemUser()).thenReturn(true);
+ when(mContext.userManager.canAddMoreManagedProfiles(DpmMockContext.CALLER_USER_HANDLE,
+ true)).thenReturn(true);
+ setUserSetupCompleteForUser(true, DpmMockContext.CALLER_USER_HANDLE);
+
+ mContext.binder.callingUid = DpmMockContext.CALLER_UID;
+
+ assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE,
+ true/* it's undefined behavior. Can be changed into false in the future */);
+ assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, true);
+ assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE,
+ true/* it's undefined behavior. Can be changed into false in the future */);
+ assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_USER,
+ false/* because user setup completed */);
+ }
+
+ public void testIsProvisioningAllowed_provisionManagedProfileWithDeviceOwner_systemUser()
+ throws Exception {
+ setDeviceOwner();
+
+ when(mContext.ipackageManager.hasSystemFeature(PackageManager.FEATURE_MANAGED_USERS, 0))
+ .thenReturn(true);
+ when(mContext.userManagerForMock.isSplitSystemUser()).thenReturn(true);
+ when(mContext.userManager.canAddMoreManagedProfiles(UserHandle.USER_SYSTEM, true))
+ .thenReturn(false);
+ setUserSetupCompleteForUser(true, UserHandle.USER_SYSTEM);
+
+ mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
+
+ assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE,
+ false /* can't provision managed profile on system user */);
+ }
+
+ public void testIsProvisioningAllowed_provisionManagedProfileWithDeviceOwner_primaryUser()
+ throws Exception {
+ setDeviceOwner();
+
+ when(mContext.ipackageManager.hasSystemFeature(PackageManager.FEATURE_MANAGED_USERS, 0))
+ .thenReturn(true);
+ when(mContext.userManagerForMock.isSplitSystemUser()).thenReturn(true);
+ when(mContext.userManager.canAddMoreManagedProfiles(DpmMockContext.CALLER_USER_HANDLE,
+ true)).thenReturn(true);
+ setUserSetupCompleteForUser(false, DpmMockContext.CALLER_USER_HANDLE);
+
+ mContext.binder.callingUid = DpmMockContext.CALLER_UID;
+
+ assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, true);
+ }
+
+ private void setUserSetupCompleteForUser(boolean isUserSetupComplete, int userhandle) {
+ when(mContext.settings.settingsSecureGetIntForUser(Settings.Secure.USER_SETUP_COMPLETE, 0,
+ userhandle)).thenReturn(isUserSetupComplete ? 1 : 0);
+ dpms.notifyChangeToContentObserver(
+ Settings.Secure.getUriFor(Settings.Secure.USER_SETUP_COMPLETE), userhandle);
+ }
+
+ private void assertProvisioningAllowed(String action, boolean expected) {
+ assertEquals("isProvisioningAllowed(" + action + ") returning unexpected result", expected,
+ dpm.isProvisioningAllowed(action));
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
index 8e2ef70..60d7382 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
@@ -53,6 +53,7 @@
import java.util.ArrayList;
import java.util.List;
+import static org.mockito.Matchers.anyBoolean;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.mock;
@@ -172,36 +173,36 @@
}
public static class SettingsForMock {
- int settingsSecureGetIntForUser(String name, int def, int userHandle) {
+ public int settingsSecureGetIntForUser(String name, int def, int userHandle) {
return 0;
}
- void settingsSecurePutIntForUser(String name, int value, int userHandle) {
+ public void settingsSecurePutIntForUser(String name, int value, int userHandle) {
}
- void settingsSecurePutStringForUser(String name, String value, int userHandle) {
+ public void settingsSecurePutStringForUser(String name, String value, int userHandle) {
}
- void settingsGlobalPutStringForUser(String name, String value, int userHandle) {
+ public void settingsGlobalPutStringForUser(String name, String value, int userHandle) {
}
- void settingsSecurePutInt(String name, int value) {
+ public void settingsSecurePutInt(String name, int value) {
}
- void settingsGlobalPutInt(String name, int value) {
+ public void settingsGlobalPutInt(String name, int value) {
}
- void settingsSecurePutString(String name, String value) {
+ public void settingsSecurePutString(String name, String value) {
}
- void settingsGlobalPutString(String name, String value) {
+ public void settingsGlobalPutString(String name, String value) {
}
- int settingsGlobalGetInt(String name, int def) {
+ public int settingsGlobalGetInt(String name, int value) {
return 0;
}
- void securityLogSetLoggingEnabledProperty(boolean enabled) {
+ public void securityLogSetLoggingEnabledProperty(boolean enabled) {
}
public boolean securityLogGetLoggingEnabledProperty() {
@@ -321,6 +322,8 @@
mUserInfos.add(uh);
when(userManager.getUsers()).thenReturn(mUserInfos);
+ when(userManager.getUsers(anyBoolean())).thenReturn(mUserInfos);
+ when(userManager.isUserRunning(eq(new UserHandle(userId)))).thenReturn(true);
when(userManager.getUserInfo(anyInt())).thenAnswer(
new Answer<UserInfo>() {
@Override
diff --git a/services/tests/servicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java b/services/tests/servicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java
new file mode 100644
index 0000000..83a59fd
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java
@@ -0,0 +1,541 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.server.notification;
+
+
+import android.app.ActivityManager;
+import android.app.Notification;
+import android.app.Notification.Builder;
+import android.media.AudioAttributes;
+import android.media.AudioManager;
+import android.net.Uri;
+import android.os.Handler;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.os.Vibrator;
+import android.service.notification.NotificationListenerService.Ranking;
+import android.service.notification.StatusBarNotification;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+
+import static org.mockito.Matchers.anyBoolean;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.anyObject;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+public class BuzzBeepBlinkTest extends AndroidTestCase {
+
+ @Mock AudioManager mAudioManager;
+ @Mock Vibrator mVibrator;
+ @Mock android.media.IRingtonePlayer mRingtonePlayer;
+ @Mock Handler mHandler;
+
+ private NotificationManagerService mService;
+ private String mPkg = "com.android.server.notification";
+ private int mId = 1001;
+ private int mOtherId = 1002;
+ private String mTag = null;
+ private int mUid = 1000;
+ private int mPid = 2000;
+ private int mScore = 10;
+ private android.os.UserHandle mUser = UserHandle.of(ActivityManager.getCurrentUser());
+
+ @Override
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+
+ when(mAudioManager.isAudioFocusExclusive()).thenReturn(false);
+ when(mAudioManager.getRingtonePlayer()).thenReturn(mRingtonePlayer);
+ when(mAudioManager.getStreamVolume(anyInt())).thenReturn(10);
+ when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_NORMAL);
+
+ mService = new NotificationManagerService(getContext());
+ mService.setAudioManager(mAudioManager);
+ mService.setVibrator(mVibrator);
+ mService.setSystemReady(true);
+ mService.setHandler(mHandler);
+ }
+
+ //
+ // Convenience functions for creating notification records
+ //
+
+ private NotificationRecord getNoisyOtherNotification() {
+ return getNotificationRecord(mOtherId, false /* insistent */, false /* once */,
+ true /* noisy */, true /* buzzy*/);
+ }
+
+ private NotificationRecord getBeepyNotification() {
+ return getNotificationRecord(mId, false /* insistent */, false /* once */,
+ true /* noisy */, false /* buzzy*/);
+ }
+
+ private NotificationRecord getBeepyOnceNotification() {
+ return getNotificationRecord(mId, false /* insistent */, true /* once */,
+ true /* noisy */, false /* buzzy*/);
+ }
+
+ private NotificationRecord getQuietNotification() {
+ return getNotificationRecord(mId, false /* insistent */, false /* once */,
+ false /* noisy */, false /* buzzy*/);
+ }
+
+ private NotificationRecord getQuietOtherNotification() {
+ return getNotificationRecord(mOtherId, false /* insistent */, false /* once */,
+ false /* noisy */, false /* buzzy*/);
+ }
+
+ private NotificationRecord getQuietOnceNotification() {
+ return getNotificationRecord(mId, false /* insistent */, true /* once */,
+ false /* noisy */, false /* buzzy*/);
+ }
+
+ private NotificationRecord getInsistentBeepyNotification() {
+ return getNotificationRecord(mId, true /* insistent */, false /* once */,
+ true /* noisy */, false /* buzzy*/);
+ }
+
+ private NotificationRecord getBuzzyNotification() {
+ return getNotificationRecord(mId, false /* insistent */, false /* once */,
+ false /* noisy */, true /* buzzy*/);
+ }
+
+ private NotificationRecord getBuzzyOnceNotification() {
+ return getNotificationRecord(mId, false /* insistent */, true /* once */,
+ false /* noisy */, true /* buzzy*/);
+ }
+
+ private NotificationRecord getInsistentBuzzyNotification() {
+ return getNotificationRecord(mId, true /* insistent */, false /* once */,
+ false /* noisy */, true /* buzzy*/);
+ }
+
+ private NotificationRecord getNotificationRecord(int id, boolean insistent, boolean once,
+ boolean noisy, boolean buzzy) {
+ final Builder builder = new Builder(getContext())
+ .setContentTitle("foo")
+ .setSmallIcon(android.R.drawable.sym_def_app_icon)
+ .setPriority(Notification.PRIORITY_HIGH)
+ .setOnlyAlertOnce(once);
+
+ int defaults = 0;
+ if (noisy) {
+ defaults |= Notification.DEFAULT_SOUND;
+ }
+ if (buzzy) {
+ defaults |= Notification.DEFAULT_VIBRATE;
+ }
+ builder.setDefaults(defaults);
+
+ Notification n = builder.build();
+ if (insistent) {
+ n.flags |= Notification.FLAG_INSISTENT;
+ }
+ StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, id, mTag, mUid, mPid,
+ mScore, n, mUser, System.currentTimeMillis());
+ return new NotificationRecord(getContext(), sbn);
+ }
+
+ //
+ // Convenience functions for interacting with mocks
+ //
+
+ private void verifyNeverBeep() throws RemoteException {
+ verify(mRingtonePlayer, never()).playAsync((Uri) anyObject(), (UserHandle) anyObject(),
+ anyBoolean(), (AudioAttributes) anyObject());
+ }
+
+ private void verifyBeep() throws RemoteException {
+ verify(mRingtonePlayer, times(1)).playAsync((Uri) anyObject(), (UserHandle) anyObject(),
+ eq(true), (AudioAttributes) anyObject());
+ }
+
+ private void verifyBeepLooped() throws RemoteException {
+ verify(mRingtonePlayer, times(1)).playAsync((Uri) anyObject(), (UserHandle) anyObject(),
+ eq(false), (AudioAttributes) anyObject());
+ }
+
+ private void verifyNeverStopAudio() throws RemoteException {
+ verify(mRingtonePlayer, never()).stopAsync();
+ }
+
+ private void verifyStopAudio() throws RemoteException {
+ verify(mRingtonePlayer, times(1)).stopAsync();
+ }
+
+ private void verifyNeverVibrate() {
+ verify(mVibrator, never()).vibrate(anyInt(), anyString(), (long[]) anyObject(),
+ anyInt(), (AudioAttributes) anyObject());
+ }
+
+ private void verifyVibrate() {
+ verify(mVibrator, times(1)).vibrate(anyInt(), anyString(), (long[]) anyObject(),
+ eq(-1), (AudioAttributes) anyObject());
+ }
+
+ private void verifyVibrateLooped() {
+ verify(mVibrator, times(1)).vibrate(anyInt(), anyString(), (long[]) anyObject(),
+ eq(0), (AudioAttributes) anyObject());
+ }
+
+ private void verifyStopVibrate() {
+ verify(mVibrator, times(1)).cancel();
+ }
+
+ private void verifyNeverStopVibrate() throws RemoteException {
+ verify(mVibrator, never()).cancel();
+ }
+
+ @SmallTest
+ public void testBeep() throws Exception {
+ NotificationRecord r = getBeepyNotification();
+
+ mService.buzzBeepBlinkLocked(r);
+
+ verifyBeepLooped();
+ verifyNeverVibrate();
+ }
+
+ //
+ // Tests
+ //
+
+ @SmallTest
+ public void testBeepInsistently() throws Exception {
+ NotificationRecord r = getInsistentBeepyNotification();
+
+ mService.buzzBeepBlinkLocked(r);
+
+ verifyBeep();
+ }
+
+ @SmallTest
+ public void testNoInterruptionForMin() throws Exception {
+ NotificationRecord r = getBeepyNotification();
+ r.setImportance(Ranking.IMPORTANCE_MIN, "foo");
+
+ mService.buzzBeepBlinkLocked(r);
+
+ verifyNeverBeep();
+ verifyNeverVibrate();
+ }
+
+ @SmallTest
+ public void testNoInterruptionForIntercepted() throws Exception {
+ NotificationRecord r = getBeepyNotification();
+ r.setIntercepted(true);
+
+ mService.buzzBeepBlinkLocked(r);
+
+ verifyNeverBeep();
+ verifyNeverVibrate();
+ }
+
+ @SmallTest
+ public void testBeepTwice() throws Exception {
+ NotificationRecord r = getBeepyNotification();
+
+ // set up internal state
+ mService.buzzBeepBlinkLocked(r);
+ Mockito.reset(mRingtonePlayer);
+
+ // update should beep
+ r.isUpdate = true;
+ mService.buzzBeepBlinkLocked(r);
+ verifyBeepLooped();
+ }
+
+ @SmallTest
+ public void testHonorAlertOnlyOnceForBeep() throws Exception {
+ NotificationRecord r = getBeepyNotification();
+ NotificationRecord s = getBeepyOnceNotification();
+ s.isUpdate = true;
+
+ // set up internal state
+ mService.buzzBeepBlinkLocked(r);
+ Mockito.reset(mRingtonePlayer);
+
+ // update should not beep
+ mService.buzzBeepBlinkLocked(s);
+ verifyNeverBeep();
+ }
+
+ @SmallTest
+ public void testNoisyUpdateDoesNotCancelAudio() throws Exception {
+ NotificationRecord r = getBeepyNotification();
+
+ mService.buzzBeepBlinkLocked(r);
+ r.isUpdate = true;
+ mService.buzzBeepBlinkLocked(r);
+
+ verifyNeverStopAudio();
+ }
+
+ @SmallTest
+ public void testNoisyOnceUpdateDoesNotCancelAudio() throws Exception {
+ NotificationRecord r = getBeepyNotification();
+ NotificationRecord s = getBeepyOnceNotification();
+ s.isUpdate = true;
+
+ mService.buzzBeepBlinkLocked(r);
+ mService.buzzBeepBlinkLocked(s);
+
+ verifyNeverStopAudio();
+ }
+
+ @SmallTest
+ public void testQuietUpdateDoesNotCancelAudioFromOther() throws Exception {
+ NotificationRecord r = getBeepyNotification();
+ NotificationRecord s = getQuietNotification();
+ s.isUpdate = true;
+ NotificationRecord other = getNoisyOtherNotification();
+
+ // set up internal state
+ mService.buzzBeepBlinkLocked(r);
+ mService.buzzBeepBlinkLocked(other); // this takes the audio stream
+ Mockito.reset(mRingtonePlayer);
+
+ // should not stop noise, since we no longer own it
+ mService.buzzBeepBlinkLocked(s); // this no longer owns the stream
+ verifyNeverStopAudio();
+ }
+
+ @SmallTest
+ public void testQuietInterloperDoesNotCancelAudio() throws Exception {
+ NotificationRecord r = getBeepyNotification();
+ NotificationRecord other = getQuietOtherNotification();
+
+ // set up internal state
+ mService.buzzBeepBlinkLocked(r);
+ Mockito.reset(mRingtonePlayer);
+
+ // should not stop noise, since it does not own it
+ mService.buzzBeepBlinkLocked(other);
+ verifyNeverStopAudio();
+ }
+
+ @SmallTest
+ public void testQuietUpdateCancelsAudio() throws Exception {
+ NotificationRecord r = getBeepyNotification();
+ NotificationRecord s = getQuietNotification();
+ s.isUpdate = true;
+
+ // set up internal state
+ mService.buzzBeepBlinkLocked(r);
+ Mockito.reset(mRingtonePlayer);
+
+ // quiet update should stop making noise
+ mService.buzzBeepBlinkLocked(s);
+ verifyStopAudio();
+ }
+
+ @SmallTest
+ public void testQuietOnceUpdateCancelsAudio() throws Exception {
+ NotificationRecord r = getBeepyNotification();
+ NotificationRecord s = getQuietOnceNotification();
+ s.isUpdate = true;
+
+ // set up internal state
+ mService.buzzBeepBlinkLocked(r);
+ Mockito.reset(mRingtonePlayer);
+
+ // stop making noise - this is a weird corner case, but quiet should override once
+ mService.buzzBeepBlinkLocked(s);
+ verifyStopAudio();
+ }
+
+ @SmallTest
+ public void testDemoteSoundToVibrate() throws Exception {
+ NotificationRecord r = getBeepyNotification();
+
+ // the phone is quiet
+ when(mAudioManager.getStreamVolume(anyInt())).thenReturn(0);
+ when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_VIBRATE);
+
+ mService.buzzBeepBlinkLocked(r);
+
+ verifyNeverBeep();
+ verifyVibrate();
+ }
+
+ @SmallTest
+ public void testDemotInsistenteSoundToVibrate() throws Exception {
+ NotificationRecord r = getInsistentBeepyNotification();
+
+ // the phone is quiet
+ when(mAudioManager.getStreamVolume(anyInt())).thenReturn(0);
+ when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_VIBRATE);
+
+ mService.buzzBeepBlinkLocked(r);
+
+ verifyVibrateLooped();
+ }
+
+ @SmallTest
+ public void testVibrate() throws Exception {
+ NotificationRecord r = getBuzzyNotification();
+
+ mService.buzzBeepBlinkLocked(r);
+
+ verifyNeverBeep();
+ verifyVibrate();
+ }
+
+ @SmallTest
+ public void testInsistenteVibrate() throws Exception {
+ NotificationRecord r = getInsistentBuzzyNotification();
+
+ mService.buzzBeepBlinkLocked(r);
+ verifyVibrateLooped();
+ }
+
+ @SmallTest
+ public void testVibratTwice() throws Exception {
+ NotificationRecord r = getBuzzyNotification();
+
+ // set up internal state
+ mService.buzzBeepBlinkLocked(r);
+ Mockito.reset(mVibrator);
+
+ // update should vibrate
+ r.isUpdate = true;
+ mService.buzzBeepBlinkLocked(r);
+ verifyVibrate();
+ }
+
+ @SmallTest
+ public void testHonorAlertOnlyOnceForBuzz() throws Exception {
+ NotificationRecord r = getBuzzyNotification();
+ NotificationRecord s = getBuzzyOnceNotification();
+ s.isUpdate = true;
+
+ // set up internal state
+ mService.buzzBeepBlinkLocked(r);
+ Mockito.reset(mVibrator);
+
+ // update should not beep
+ mService.buzzBeepBlinkLocked(s);
+ verifyNeverVibrate();
+ }
+
+ @SmallTest
+ public void testNoisyUpdateDoesNotCancelVibrate() throws Exception {
+ NotificationRecord r = getBuzzyNotification();
+
+ mService.buzzBeepBlinkLocked(r);
+ r.isUpdate = true;
+ mService.buzzBeepBlinkLocked(r);
+
+ verifyNeverStopVibrate();
+ }
+
+ @SmallTest
+ public void testNoisyOnceUpdateDoesNotCancelVibrate() throws Exception {
+ NotificationRecord r = getBuzzyNotification();
+ NotificationRecord s = getBuzzyOnceNotification();
+ s.isUpdate = true;
+
+ mService.buzzBeepBlinkLocked(r);
+ mService.buzzBeepBlinkLocked(s);
+
+ verifyNeverStopVibrate();
+ }
+
+ @SmallTest
+ public void testQuietUpdateDoesNotCancelVibrateFromOther() throws Exception {
+ NotificationRecord r = getBuzzyNotification();
+ NotificationRecord s = getQuietNotification();
+ s.isUpdate = true;
+ NotificationRecord other = getNoisyOtherNotification();
+
+ // set up internal state
+ mService.buzzBeepBlinkLocked(r);
+ mService.buzzBeepBlinkLocked(other); // this takes the vibrate stream
+ Mockito.reset(mVibrator);
+
+ // should not stop vibrate, since we no longer own it
+ mService.buzzBeepBlinkLocked(s); // this no longer owns the stream
+ verifyNeverStopVibrate();
+ }
+
+ @SmallTest
+ public void testQuietInterloperDoesNotCancelVibrate() throws Exception {
+ NotificationRecord r = getBuzzyNotification();
+ NotificationRecord other = getQuietOtherNotification();
+
+ // set up internal state
+ mService.buzzBeepBlinkLocked(r);
+ Mockito.reset(mVibrator);
+
+ // should not stop noise, since it does not own it
+ mService.buzzBeepBlinkLocked(other);
+ verifyNeverStopVibrate();
+ }
+
+ @SmallTest
+ public void testQuietUpdateCancelsVibrate() throws Exception {
+ NotificationRecord r = getBuzzyNotification();
+ NotificationRecord s = getQuietNotification();
+ s.isUpdate = true;
+
+ // set up internal state
+ mService.buzzBeepBlinkLocked(r);
+
+ // quiet update should stop making noise
+ mService.buzzBeepBlinkLocked(s);
+ verifyStopVibrate();
+ }
+
+ @SmallTest
+ public void testQuietOnceUpdateCancelsvibrate() throws Exception {
+ NotificationRecord r = getBuzzyNotification();
+ NotificationRecord s = getQuietOnceNotification();
+ s.isUpdate = true;
+
+ // set up internal state
+ mService.buzzBeepBlinkLocked(r);
+ Mockito.reset(mVibrator);
+
+ // stop making noise - this is a weird corner case, but quiet should override once
+ mService.buzzBeepBlinkLocked(s);
+ verifyStopVibrate();
+ }
+
+ @SmallTest
+ public void testQuietUpdateCancelsDemotedVibrate() throws Exception {
+ NotificationRecord r = getBeepyNotification();
+ NotificationRecord s = getQuietNotification();
+
+ // the phone is quiet
+ when(mAudioManager.getStreamVolume(anyInt())).thenReturn(0);
+ when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_VIBRATE);
+
+ mService.buzzBeepBlinkLocked(r);
+
+ // quiet update should stop making noise
+ mService.buzzBeepBlinkLocked(s);
+ verifyStopVibrate();
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutInfoTest.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutInfoTest.java
deleted file mode 100644
index eb16a1d..0000000
--- a/services/tests/servicestests/src/com/android/server/pm/ShortcutInfoTest.java
+++ /dev/null
@@ -1,44 +0,0 @@
-
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.server.pm;
-
-import android.content.pm.ShortcutInfo;
-import android.test.AndroidTestCase;
-
-import com.android.server.testutis.TestUtils;
-
-/**
- * Tests for {@link ShortcutInfo}.
-
- m FrameworksServicesTests &&
- adb install \
- -r -g ${ANDROID_PRODUCT_OUT}/data/app/FrameworksServicesTests/FrameworksServicesTests.apk &&
- adb shell am instrument -e class com.android.server.pm.ShortcutInfoTest \
- -w com.android.frameworks.servicestests/android.support.test.runner.AndroidJUnitRunner
-
- */
-public class ShortcutInfoTest extends AndroidTestCase {
-
- public void testNoId() {
- TestUtils.assertExpectException(
- IllegalArgumentException.class,
- "ID must be provided",
- () -> new ShortcutInfo.Builder(mContext).build());
- }
-
- // TODO Add more tests.
-}
diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest.java
index 28966ca..baa5d36 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest.java
@@ -16,15 +16,21 @@
package com.android.server.pm;
import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.anyList;
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
import android.annotation.UserIdInt;
import android.app.Activity;
import android.content.BroadcastReceiver;
@@ -32,25 +38,32 @@
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.pm.ApplicationInfo;
import android.content.pm.ILauncherApps;
import android.content.pm.LauncherApps;
import android.content.pm.LauncherApps.ShortcutQuery;
+import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManagerInternal;
import android.content.pm.ShortcutInfo;
import android.content.pm.ShortcutManager;
import android.content.pm.ShortcutServiceInternal;
+import android.content.pm.Signature;
+import android.content.pm.UserInfo;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.Bitmap.CompressFormat;
import android.graphics.BitmapFactory;
import android.graphics.drawable.Icon;
+import android.net.Uri;
import android.os.BaseBundle;
import android.os.Bundle;
import android.os.FileUtils;
import android.os.Handler;
import android.os.Looper;
+import android.os.Parcel;
import android.os.ParcelFileDescriptor;
+import android.os.PersistableBundle;
import android.os.Process;
import android.os.UserHandle;
import android.os.UserManager;
@@ -59,6 +72,7 @@
import android.test.suitebuilder.annotation.SmallTest;
import android.util.ArraySet;
import android.util.Log;
+import android.util.Pair;
import android.util.SparseArray;
import com.android.frameworks.servicestests.R;
@@ -68,6 +82,8 @@
import com.android.server.pm.LauncherAppsService.LauncherAppsImpl;
import com.android.server.pm.ShortcutService.ConfigConstants;
import com.android.server.pm.ShortcutService.FileOutputStreamWithPath;
+import com.android.server.pm.ShortcutUser.PackageWithUser;
+import com.android.server.testutis.TestUtils;
import libcore.io.IoUtils;
@@ -88,6 +104,8 @@
import java.util.List;
import java.util.Map;
import java.util.Set;
+import java.util.function.BiPredicate;
+import java.util.function.Consumer;
/**
* Tests for ShortcutService and ShortcutManager.
@@ -99,11 +117,8 @@
-w com.android.frameworks.servicestests/android.support.test.runner.AndroidJUnitRunner
* TODO: Add checks with assertAllNotHaveIcon()
- *
- * TODO: separate, detailed tests for ShortcutInfo (CTS?) *
- *
- * TODO: Cross-user test (do in CTS?)
- *
+ * TODO: Detailed test for hasShortcutPermissionInner().
+ * TODO: Add tests for the command line functions too.
*/
@SmallTest
public class ShortcutManagerTest extends InstrumentationTestCase {
@@ -115,7 +130,10 @@
*/
private static final boolean ENABLE_DUMP = false; // DO NOT SUBMIT WITH true
- private class BaseContext extends MockContext {
+ private static final boolean DUMP_IN_TEARDOWN = false; // DO NOT SUBMIT WITH true
+
+ // public for mockito
+ public class BaseContext extends MockContext {
@Override
public Object getSystemService(String name) {
switch (name) {
@@ -149,7 +167,7 @@
}
/** Context used in the client side */
- private class ClientContext extends BaseContext {
+ public class ClientContext extends BaseContext {
@Override
public String getPackageName() {
return mInjectedClientPackage;
@@ -157,7 +175,7 @@
}
/** Context used in the service side */
- private final class ServiceContext extends BaseContext {
+ public class ServiceContext extends BaseContext {
long injectClearCallingIdentity() {
final int prevCallingUid = mInjectedCallingUid;
mInjectedCallingUid = Process.SYSTEM_UID;
@@ -167,6 +185,11 @@
void injectRestoreCallingIdentity(long token) {
mInjectedCallingUid = (int) token;
}
+
+ @Override
+ public void startActivityAsUser(@RequiresPermission Intent intent, @Nullable Bundle options,
+ UserHandle userId) {
+ }
}
/** ShortcutService with injection override methods. */
@@ -217,8 +240,7 @@
@Override
int injectGetPackageUid(String packageName, int userId) {
- Integer uid = mInjectedPackageUidMap.get(packageName);
- return UserHandle.getUid(getCallingUserId(), (uid != null ? uid : 0));
+ return getInjectedPackageInfo(packageName, userId, false).applicationInfo.uid;
}
@Override
@@ -248,19 +270,25 @@
@Override
boolean hasShortcutHostPermission(@NonNull String callingPackage, int userId) {
- // Sort of hack; do a simpler check.
- return LAUNCHER_1.equals(callingPackage) || LAUNCHER_2.equals(callingPackage);
+ return mDefaultLauncherChecker.test(callingPackage, userId);
+ }
+
+ @Override
+ PackageInfo injectPackageInfo(String packageName, @UserIdInt int userId,
+ boolean getSignatures) {
+ return getInjectedPackageInfo(packageName, userId, getSignatures);
+ }
+
+ @Override
+ ApplicationInfo injectApplicationInfo(String packageName, @UserIdInt int userId) {
+ PackageInfo pi = injectPackageInfo(packageName, userId, /* getSignatures= */ false);
+ return pi != null ? pi.applicationInfo : null;
}
@Override
void postToHandler(Runnable r) {
final long token = mContext.injectClearCallingIdentity();
- super.postToHandler(r);
- try {
- runTestOnUiThread(() -> {});
- } catch (Throwable e) {
- fail("runTestOnUiThread failed: " + e);
- }
+ r.run();
mContext.injectRestoreCallingIdentity(token);
}
@@ -292,33 +320,33 @@
}
@Override
- public void ensureInUserProfiles(UserHandle userToCheck, String message) {
- if (getCallingUserId() == userToCheck.getIdentifier()) {
- return; // okay
- }
-
- assertEquals(Process.SYSTEM_UID, mInjectedCallingUid);
- // SKIP
- }
-
- @Override
public void verifyCallingPackage(String callingPackage) {
// SKIP
}
@Override
- boolean isEnabledProfileOf(UserHandle user, UserHandle listeningUser, String debugMsg) {
- // This requires CROSS_USER
- assertEquals(Process.SYSTEM_UID, mInjectedCallingUid);
- return user.getIdentifier() == listeningUser.getIdentifier();
- }
-
- @Override
void postToPackageMonitorHandler(Runnable r) {
final long token = mContext.injectClearCallingIdentity();
r.run();
mContext.injectRestoreCallingIdentity(token);
}
+
+ @Override
+ int injectBinderCallingUid() {
+ return mInjectedCallingUid;
+ }
+
+ @Override
+ long injectClearCallingIdentity() {
+ final int prevCallingUid = mInjectedCallingUid;
+ mInjectedCallingUid = Process.SYSTEM_UID;
+ return prevCallingUid;
+ }
+
+ @Override
+ void injectRestoreCallingIdentity(long token) {
+ mInjectedCallingUid = (int) token;
+ }
}
private class LauncherAppsTestable extends LauncherApps {
@@ -344,7 +372,11 @@
private ShortcutServiceInternal mInternal;
private LauncherAppImplTestable mLauncherAppImpl;
- private LauncherAppsTestable mLauncherApps;
+
+ // LauncherApps has per-instace state, so we need a differnt instance for each launcher.
+ private final Map<Pair<Integer, String>, LauncherAppsTestable>
+ mLauncherAppsMap = new HashMap<>();
+ private LauncherAppsTestable mLauncherApps; // Current one
private File mInjectedFilePathRoot;
@@ -355,7 +387,9 @@
private int mInjectedCallingUid;
private String mInjectedClientPackage;
- private Map<String, Integer> mInjectedPackageUidMap;
+ private Map<String, PackageInfo> mInjectedPackages;
+
+ private Set<PackageWithUser> mUninstalledPackages;
private PackageManager mMockPackageManager;
private PackageManagerInternal mMockPackageManagerInternal;
@@ -370,15 +404,49 @@
private static final String CALLING_PACKAGE_3 = "com.android.test.3";
private static final int CALLING_UID_3 = 10003;
+ private static final String CALLING_PACKAGE_4 = "com.android.test.4";
+ private static final int CALLING_UID_4 = 10004;
+
private static final String LAUNCHER_1 = "com.android.launcher.1";
private static final int LAUNCHER_UID_1 = 10011;
private static final String LAUNCHER_2 = "com.android.launcher.2";
private static final int LAUNCHER_UID_2 = 10012;
+ private static final String LAUNCHER_3 = "com.android.launcher.3";
+ private static final int LAUNCHER_UID_3 = 10013;
+
+ private static final String LAUNCHER_4 = "com.android.launcher.4";
+ private static final int LAUNCHER_UID_4 = 10014;
+
private static final int USER_0 = UserHandle.USER_SYSTEM;
private static final int USER_10 = 10;
private static final int USER_11 = 11;
+ private static final int USER_P0 = 20; // profile of user 0
+
+ private static final UserHandle HANDLE_USER_0 = UserHandle.of(USER_0);
+ private static final UserHandle HANDLE_USER_10 = UserHandle.of(USER_10);
+ private static final UserHandle HANDLE_USER_11 = UserHandle.of(USER_11);
+ private static final UserHandle HANDLE_USER_P0 = UserHandle.of(USER_P0);
+
+ private static final UserInfo USER_INFO_0 = withProfileGroupId(
+ new UserInfo(USER_0, "user0",
+ UserInfo.FLAG_ADMIN | UserInfo.FLAG_PRIMARY | UserInfo.FLAG_INITIALIZED), 10);
+
+ private static final UserInfo USER_INFO_10 =
+ new UserInfo(USER_10, "user10", UserInfo.FLAG_INITIALIZED);
+
+ private static final UserInfo USER_INFO_11 =
+ new UserInfo(USER_11, "user11", UserInfo.FLAG_INITIALIZED);
+
+ private static final UserInfo USER_INFO_P0 = withProfileGroupId(
+ new UserInfo(USER_P0, "userP0",
+ UserInfo.FLAG_MANAGED_PROFILE), 10);
+
+ private BiPredicate<String, Integer> mDefaultLauncherChecker =
+ (callingPackage, userId) ->
+ LAUNCHER_1.equals(callingPackage) || LAUNCHER_2.equals(callingPackage)
+ || LAUNCHER_3.equals(callingPackage) || LAUNCHER_4.equals(callingPackage);
private static final long START_TIME = 1440000000101L;
@@ -392,11 +460,18 @@
private static final int MAX_ICON_DIMENSION_LOWRAM = 32;
+ private static final ShortcutQuery QUERY_ALL = new ShortcutQuery();
+
+ static {
+ QUERY_ALL.setQueryFlags(
+ ShortcutQuery.FLAG_GET_DYNAMIC | ShortcutQuery.FLAG_GET_PINNED);
+ }
+
@Override
protected void setUp() throws Exception {
super.setUp();
- mServiceContext = new ServiceContext();
+ mServiceContext = spy(new ServiceContext());
mClientContext = new ClientContext();
mMockPackageManager = mock(PackageManager.class);
@@ -407,32 +482,87 @@
mInjectedCurrentTimeLillis = START_TIME;
- mInjectedPackageUidMap = new HashMap<>();
- mInjectedPackageUidMap.put(CALLING_PACKAGE_1, CALLING_UID_1);
- mInjectedPackageUidMap.put(CALLING_PACKAGE_2, CALLING_UID_2);
- mInjectedPackageUidMap.put(CALLING_PACKAGE_3, CALLING_UID_3);
- mInjectedPackageUidMap.put(LAUNCHER_1, LAUNCHER_UID_1);
- mInjectedPackageUidMap.put(LAUNCHER_2, LAUNCHER_UID_2);
+ mInjectedPackages = new HashMap<>();;
+ addPackage(CALLING_PACKAGE_1, CALLING_UID_1, 1);
+ addPackage(CALLING_PACKAGE_2, CALLING_UID_2, 2);
+ addPackage(CALLING_PACKAGE_3, CALLING_UID_3, 3);
+ addPackage(CALLING_PACKAGE_4, CALLING_UID_4, 10);
+ addPackage(LAUNCHER_1, LAUNCHER_UID_1, 4);
+ addPackage(LAUNCHER_2, LAUNCHER_UID_2, 5);
+ addPackage(LAUNCHER_3, LAUNCHER_UID_3, 6);
+ addPackage(LAUNCHER_4, LAUNCHER_UID_4, 10);
+
+ // CALLING_PACKAGE_3 / LAUNCHER_3 are not backup target.
+ updatePackageInfo(CALLING_PACKAGE_3,
+ pi -> pi.applicationInfo.flags &= ~ApplicationInfo.FLAG_ALLOW_BACKUP);
+ updatePackageInfo(LAUNCHER_3,
+ pi -> pi.applicationInfo.flags &= ~ApplicationInfo.FLAG_ALLOW_BACKUP);
+
+ mUninstalledPackages = new HashSet<>();
mInjectedFilePathRoot = new File(getTestContext().getCacheDir(), "test-files");
- // Empty the data directory.
- if (mInjectedFilePathRoot.exists()) {
- Assert.assertTrue("failed to delete dir",
- FileUtils.deleteContents(mInjectedFilePathRoot));
- }
- mInjectedFilePathRoot.mkdirs();
+ deleteAllSavedFiles();
+
+ // Set up users.
+ doAnswer(inv -> {
+ assertSystem();
+ return USER_INFO_0;
+ }).when(mMockUserManager).getUserInfo(eq(USER_0));
+
+ doAnswer(inv -> {
+ assertSystem();
+ return USER_INFO_10;
+ }).when(mMockUserManager).getUserInfo(eq(USER_10));
+
+ doAnswer(inv -> {
+ assertSystem();
+ return USER_INFO_11;
+ }).when(mMockUserManager).getUserInfo(eq(USER_11));
+
+ doAnswer(inv -> {
+ assertSystem();
+ return USER_INFO_P0;
+ }).when(mMockUserManager).getUserInfo(eq(USER_P0));
+
+ // User 0 is always running.
+ when(mMockUserManager.isUserRunning(eq(USER_0))).thenReturn(true);
initService();
setCaller(CALLING_PACKAGE_1);
}
+ private static UserInfo withProfileGroupId(UserInfo in, int groupId) {
+ in.profileGroupId = groupId;
+ return in;
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ if (DUMP_IN_TEARDOWN) dumpsysOnLogcat("Teardown");
+
+ shutdownServices();
+
+ super.tearDown();
+ }
+
private Context getTestContext() {
return getInstrumentation().getContext();
}
+ private void deleteAllSavedFiles() {
+ // Empty the data directory.
+ if (mInjectedFilePathRoot.exists()) {
+ Assert.assertTrue("failed to delete dir",
+ FileUtils.deleteContents(mInjectedFilePathRoot));
+ }
+ mInjectedFilePathRoot.mkdirs();
+ }
+
/** (Re-) init the manager and the service. */
private void initService() {
+ shutdownServices();
+
LocalServices.removeServiceForTest(ShortcutServiceInternal.class);
// Instantiate targets.
@@ -442,18 +572,117 @@
mInternal = LocalServices.getService(ShortcutServiceInternal.class);
mLauncherAppImpl = new LauncherAppImplTestable(mServiceContext);
- mLauncherApps = new LauncherAppsTestable(mClientContext, mLauncherAppImpl);
+ mLauncherApps = null;
+ mLauncherAppsMap.clear();
// Load the setting file.
mService.onBootPhase(SystemService.PHASE_LOCK_SETTINGS_READY);
}
+ private void shutdownServices() {
+ if (mService != null) {
+ // Flush all the unsaved data from the previous instance.
+ mService.saveDirtyInfo();
+ }
+ LocalServices.removeServiceForTest(ShortcutServiceInternal.class);
+
+ mService = null;
+ mManager = null;
+ mInternal = null;
+ mLauncherAppImpl = null;
+ mLauncherApps = null;
+ mLauncherAppsMap.clear();
+ }
+
+ private void addPackage(String packageName, int uid, int version) {
+ addPackage(packageName, uid, version, packageName);
+ }
+
+ private <T> List<T> list(T... array) {
+ return Arrays.asList(array);
+ }
+
+ private <T> Set<T> set(Set<T> in) {
+ return new ArraySet<T>(in);
+ }
+
+ private Signature[] genSignatures(String... signatures) {
+ final Signature[] sigs = new Signature[signatures.length];
+ for (int i = 0; i < signatures.length; i++){
+ sigs[i] = new Signature(signatures[i].getBytes());
+ }
+ return sigs;
+ }
+
+ private PackageInfo genPackage(String packageName, int uid, int version, String... signatures) {
+ final PackageInfo pi = new PackageInfo();
+ pi.packageName = packageName;
+ pi.applicationInfo = new ApplicationInfo();
+ pi.applicationInfo.uid = uid;
+ pi.applicationInfo.flags = ApplicationInfo.FLAG_INSTALLED
+ | ApplicationInfo.FLAG_ALLOW_BACKUP;
+ pi.versionCode = version;
+ pi.signatures = genSignatures(signatures);
+
+ return pi;
+ }
+
+ private void addPackage(String packageName, int uid, int version, String... signatures) {
+ mInjectedPackages.put(packageName, genPackage(packageName, uid, version, signatures));
+ }
+
+ private void updatePackageInfo(String packageName, Consumer<PackageInfo> c) {
+ c.accept(mInjectedPackages.get(packageName));
+ }
+
+ private void uninstallPackage(int userId, String packageName) {
+ if (ENABLE_DUMP) {
+ Log.i(TAG, "Unnstall package " + packageName + " / " + userId);
+ }
+ mUninstalledPackages.add(PackageWithUser.of(userId, packageName));
+ }
+
+ private void installPackage(int userId, String packageName) {
+ if (ENABLE_DUMP) {
+ Log.i(TAG, "Install package " + packageName + " / " + userId);
+ }
+ mUninstalledPackages.remove(PackageWithUser.of(userId, packageName));
+ }
+
+ PackageInfo getInjectedPackageInfo(String packageName, @UserIdInt int userId,
+ boolean getSignatures) {
+ final PackageInfo pi = mInjectedPackages.get(packageName);
+ if (pi == null) return null;
+
+ final PackageInfo ret = new PackageInfo();
+ ret.packageName = pi.packageName;
+ ret.versionCode = pi.versionCode;
+ ret.applicationInfo = new ApplicationInfo(pi.applicationInfo);
+ ret.applicationInfo.uid = UserHandle.getUid(userId, pi.applicationInfo.uid);
+ if (mUninstalledPackages.contains(PackageWithUser.of(userId, packageName))) {
+ ret.applicationInfo.flags &= ~ApplicationInfo.FLAG_INSTALLED;
+ }
+
+ if (getSignatures) {
+ ret.signatures = pi.signatures;
+ }
+
+ return ret;
+ }
+
/** Replace the current calling package */
private void setCaller(String packageName, int userId) {
mInjectedClientPackage = packageName;
- mInjectedCallingUid = UserHandle.getUid(userId,
- Preconditions.checkNotNull(mInjectedPackageUidMap.get(packageName),
- "Unknown package"));
+ mInjectedCallingUid =
+ Preconditions.checkNotNull(getInjectedPackageInfo(packageName, userId, false),
+ "Unknown package").applicationInfo.uid;
+
+ // Set up LauncherApps for this caller.
+ final Pair<Integer, String> key = Pair.create(userId, packageName);
+ if (!mLauncherAppsMap.containsKey(key)) {
+ mLauncherAppsMap.put(key, new LauncherAppsTestable(mClientContext, mLauncherAppImpl));
+ }
+ mLauncherApps = mLauncherAppsMap.get(key);
}
private void setCaller(String packageName) {
@@ -464,15 +693,19 @@
return mInjectedClientPackage;
}
+ private void setDefaultLauncherChecker(BiPredicate<String, Integer> p) {
+ mDefaultLauncherChecker = p;
+ }
+
private void runWithCaller(String packageName, int userId, Runnable r) {
final String previousPackage = mInjectedClientPackage;
- final int previousUid = mInjectedCallingUid;
+ final int previousUserId = UserHandle.getUserId(mInjectedCallingUid);
setCaller(packageName, userId);
r.run();
- setCaller(previousPackage, previousUid);
+ setCaller(previousPackage, previousUserId);
}
private int getCallingUserId() {
@@ -485,14 +718,22 @@
/** For debugging */
private void dumpsysOnLogcat() {
- if (!ENABLE_DUMP) return;
+ dumpsysOnLogcat("");
+ }
+
+ private void dumpsysOnLogcat(String message) {
+ dumpsysOnLogcat(message, false);
+ }
+
+ private void dumpsysOnLogcat(String message, boolean force) {
+ if (force || !ENABLE_DUMP) return;
final ByteArrayOutputStream out = new ByteArrayOutputStream();
final PrintWriter pw = new PrintWriter(out);
mService.dumpInner(pw);
pw.close();
- Log.e(TAG, "Dumping ShortcutService:");
+ Log.e(TAG, "Dumping ShortcutService: " + message);
for (String line : out.toString().split("\n")) {
Log.e(TAG, line);
}
@@ -502,9 +743,13 @@
* For debugging, dump arbitrary file on logcat.
*/
private void dumpFileOnLogcat(String path) {
+ dumpFileOnLogcat(path, "");
+ }
+
+ private void dumpFileOnLogcat(String path, String message) {
if (!ENABLE_DUMP) return;
- Log.i(TAG, "Dumping file: " + path);
+ Log.i(TAG, "Dumping file: " + path + " " + message);
final StringBuilder sb = new StringBuilder();
try (BufferedReader br = new BufferedReader(new FileReader(path))) {
String line;
@@ -530,17 +775,21 @@
* For debugging, dump per-user state file on logcat.
*/
private void dumpUserFile(int userId) {
+ dumpUserFile(userId, "");
+ }
+
+ private void dumpUserFile(int userId, String message) {
mService.saveDirtyInfo();
dumpFileOnLogcat(mInjectedFilePathRoot.getAbsolutePath()
+ "/user-" + userId
- + "/" + ShortcutService.FILENAME_USER_PACKAGES);
+ + "/" + ShortcutService.FILENAME_USER_PACKAGES, message);
}
private void waitOnMainThread() throws Throwable {
runTestOnUiThread(() -> {});
}
- private static Bundle makeBundle(Object... keysAndValues) {
+ public static Bundle makeBundle(Object... keysAndValues) {
Preconditions.checkState((keysAndValues.length % 2) == 0);
if (keysAndValues.length == 0) {
@@ -672,6 +921,12 @@
return ret;
}
+ private static void resetAll(Collection<?> mocks) {
+ for (Object o : mocks) {
+ reset(o);
+ }
+ }
+
@NonNull
private ShortcutInfo findById(List<ShortcutInfo> list, String id) {
for (ShortcutInfo s : list) {
@@ -683,6 +938,10 @@
return null;
}
+ private void assertSystem() {
+ assertEquals("Caller must be system", Process.SYSTEM_UID, mInjectedCallingUid);
+ }
+
private void assertResetTimes(long expectedLastResetTime, long expectedNextResetTime) {
assertEquals(expectedLastResetTime, mService.getLastResetTimeLocked());
assertEquals(expectedNextResetTime, mService.getNextResetTimeLocked());
@@ -691,8 +950,7 @@
@NonNull
private List<ShortcutInfo> assertShortcutIds(@NonNull List<ShortcutInfo> actualShortcuts,
String... expectedIds) {
- assertEquals(expectedIds.length, actualShortcuts.size());
- final HashSet<String> expected = new HashSet<>(Arrays.asList(expectedIds));
+ final HashSet<String> expected = new HashSet<>(list(expectedIds));
final HashSet<String> actual = new HashSet<>();
for (ShortcutInfo s : actualShortcuts) {
actual.add(s.getId());
@@ -772,7 +1030,7 @@
private List<ShortcutInfo> assertAllHaveIcon(
@NonNull List<ShortcutInfo> actualShortcuts) {
for (ShortcutInfo s : actualShortcuts) {
- assertTrue("ID " + s.getId(), s.hasIconFile() || s.hasIconResource());
+ assertTrue("ID " + s.getId() + " has no icon ", s.hasIconFile() || s.hasIconResource());
}
return actualShortcuts;
}
@@ -781,7 +1039,8 @@
private List<ShortcutInfo> assertAllHaveFlags(@NonNull List<ShortcutInfo> actualShortcuts,
int shortcutFlags) {
for (ShortcutInfo s : actualShortcuts) {
- assertTrue("ID " + s.getId(), s.hasFlags(shortcutFlags));
+ assertTrue("ID " + s.getId() + " doesn't have flags " + shortcutFlags,
+ s.hasFlags(shortcutFlags));
}
return actualShortcuts;
}
@@ -823,6 +1082,21 @@
return actualShortcuts;
}
+ private void assertDynamicOnly(ShortcutInfo si) {
+ assertTrue(si.isDynamic());
+ assertFalse(si.isPinned());
+ }
+
+ private void assertPinnedOnly(ShortcutInfo si) {
+ assertFalse(si.isDynamic());
+ assertTrue(si.isPinned());
+ }
+
+ private void assertDynamicAndPinned(ShortcutInfo si) {
+ assertTrue(si.isDynamic());
+ assertTrue(si.isPinned());
+ }
+
private void assertBitmapSize(int expectedWidth, int expectedHeight, @NonNull Bitmap bitmap) {
assertEquals("width", expectedWidth, bitmap.getWidth());
assertEquals("height", expectedHeight, bitmap.getHeight());
@@ -864,6 +1138,39 @@
assertTrue(getPackageShortcut(packageName, shortcutId, userId) == null);
}
+ private Intent launchShortcutAndGetIntent(
+ @NonNull String packageName, @NonNull String shortcutId, int userId) {
+ reset(mServiceContext);
+ assertTrue(mLauncherApps.startShortcut(packageName, shortcutId, null, null,
+ UserHandle.of(userId)));
+
+ final ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
+ verify(mServiceContext).startActivityAsUser(
+ intentCaptor.capture(),
+ any(Bundle.class),
+ eq(UserHandle.of(userId)));
+ return intentCaptor.getValue();
+ }
+
+ private void assertShortcutLaunchable(@NonNull String packageName, @NonNull String shortcutId,
+ int userId) {
+ assertNotNull(launchShortcutAndGetIntent(packageName, shortcutId, userId));
+ }
+
+ private void assertShortcutNotLaunchable(@NonNull String packageName,
+ @NonNull String shortcutId, int userId) {
+ try {
+ final boolean ok = mLauncherApps.startShortcut(packageName, shortcutId, null, null,
+ UserHandle.of(userId));
+ if (!ok) {
+ return; // didn't launch, okay.
+ }
+ fail();
+ } catch (SecurityException expected) {
+ // security exception is okay too.
+ }
+ }
+
private ShortcutInfo getPackageShortcut(String packageName, String shortcutId) {
return getPackageShortcut(packageName, shortcutId, getCallingUserId());
}
@@ -886,11 +1193,29 @@
return getLauncherShortcuts(launcher, userId, ShortcutQuery.FLAG_GET_PINNED);
}
- /**
- * Wrap a set in an ArraySet just to get a better toString.
- */
- private <T> Set<T> set(Set<T> in) {
- return new ArraySet<T>(in);
+
+ private Intent genPackageDeleteIntent(String pakcageName, int userId) {
+ Intent i = new Intent(Intent.ACTION_PACKAGE_REMOVED);
+ i.setData(Uri.parse("package:" + pakcageName));
+ i.putExtra(Intent.EXTRA_USER_HANDLE, userId);
+ return i;
+ }
+
+ private Intent genPackageUpdateIntent(String pakcageName, int userId) {
+ Intent i = new Intent(Intent.ACTION_PACKAGE_ADDED);
+ i.setData(Uri.parse("package:" + pakcageName));
+ i.putExtra(Intent.EXTRA_USER_HANDLE, userId);
+ i.putExtra(Intent.EXTRA_REPLACING, true);
+ return i;
+ }
+
+ private ShortcutInfo parceled(ShortcutInfo si) {
+ Parcel p = Parcel.obtain();
+ p.writeParcelable(si, 0);
+ p.setDataPosition(0);
+ ShortcutInfo si2 = p.readParcelable(getClass().getClassLoader());
+ p.recycle();
+ return si2;
}
/**
@@ -1017,6 +1342,8 @@
}
public void testSetDynamicShortcuts() {
+ setCaller(CALLING_PACKAGE_1, USER_0);
+
final Icon icon1 = Icon.createWithResource(getTestContext(), R.drawable.icon1);
final Icon icon2 = Icon.createWithBitmap(BitmapFactory.decodeResource(
getTestContext().getResources(), R.drawable.icon2));
@@ -1039,7 +1366,7 @@
/* weight */ 12);
final ShortcutInfo si3 = makeShortcut("shortcut3");
- assertTrue(mManager.setDynamicShortcuts(Arrays.asList(si1, si2)));
+ assertTrue(mManager.setDynamicShortcuts(list(si1, si2)));
assertShortcutIds(assertAllNotKeyFieldsOnly(
mManager.getDynamicShortcuts()),
"shortcut1", "shortcut2");
@@ -1047,13 +1374,13 @@
// TODO: Check fields
- assertTrue(mManager.setDynamicShortcuts(Arrays.asList(si1)));
+ assertTrue(mManager.setDynamicShortcuts(list(si1)));
assertShortcutIds(assertAllNotKeyFieldsOnly(
mManager.getDynamicShortcuts()),
"shortcut1");
assertEquals(1, mManager.getRemainingCallCount());
- assertTrue(mManager.setDynamicShortcuts(Arrays.asList()));
+ assertTrue(mManager.setDynamicShortcuts(list()));
assertEquals(0, mManager.getDynamicShortcuts().size());
assertEquals(0, mManager.getRemainingCallCount());
@@ -1064,20 +1391,26 @@
dumpsysOnLogcat();
- assertTrue(mManager.setDynamicShortcuts(Arrays.asList(si2, si3)));
+ assertTrue(mManager.setDynamicShortcuts(list(si2, si3)));
assertEquals(2, mManager.getDynamicShortcuts().size());
// TODO Check max number
+
+ runWithCaller(CALLING_PACKAGE_2, USER_10, () -> {
+ assertTrue(mManager.setDynamicShortcuts(list(makeShortcut("s1"))));
+ });
}
public void testAddDynamicShortcuts() {
+ setCaller(CALLING_PACKAGE_1, USER_0);
+
final ShortcutInfo si1 = makeShortcut("shortcut1");
final ShortcutInfo si2 = makeShortcut("shortcut2");
final ShortcutInfo si3 = makeShortcut("shortcut3");
assertEquals(3, mManager.getRemainingCallCount());
- assertTrue(mManager.setDynamicShortcuts(Arrays.asList(si1)));
+ assertTrue(mManager.setDynamicShortcuts(list(si1)));
assertEquals(2, mManager.getRemainingCallCount());
assertShortcutIds(assertAllNotKeyFieldsOnly(
mManager.getDynamicShortcuts()),
@@ -1099,6 +1432,10 @@
// TODO Check max number
// TODO Check fields.
+
+ runWithCaller(CALLING_PACKAGE_2, USER_10, () -> {
+ assertTrue(mManager.addDynamicShortcut(makeShortcut("s1")));
+ });
}
public void testDeleteDynamicShortcut() {
@@ -1106,7 +1443,7 @@
final ShortcutInfo si2 = makeShortcut("shortcut2");
final ShortcutInfo si3 = makeShortcut("shortcut3");
- assertTrue(mManager.setDynamicShortcuts(Arrays.asList(si1, si2, si3)));
+ assertTrue(mManager.setDynamicShortcuts(list(si1, si2, si3)));
assertShortcutIds(assertAllNotKeyFieldsOnly(
mManager.getDynamicShortcuts()),
"shortcut1", "shortcut2", "shortcut3");
@@ -1139,8 +1476,6 @@
// Still 2 calls left.
assertEquals(2, mManager.getRemainingCallCount());
-
- // TODO Make sure pinned shortcuts won't be deleted.
}
public void testDeleteAllDynamicShortcuts() {
@@ -1148,7 +1483,7 @@
final ShortcutInfo si2 = makeShortcut("shortcut2");
final ShortcutInfo si3 = makeShortcut("shortcut3");
- assertTrue(mManager.setDynamicShortcuts(Arrays.asList(si1, si2, si3)));
+ assertTrue(mManager.setDynamicShortcuts(list(si1, si2, si3)));
assertShortcutIds(assertAllNotKeyFieldsOnly(
mManager.getDynamicShortcuts()),
"shortcut1", "shortcut2", "shortcut3");
@@ -1165,74 +1500,72 @@
assertEquals(0, mManager.getDynamicShortcuts().size());
// This should still work.
- assertTrue(mManager.setDynamicShortcuts(Arrays.asList(si1, si2, si3)));
+ assertTrue(mManager.setDynamicShortcuts(list(si1, si2, si3)));
assertEquals(3, mManager.getDynamicShortcuts().size());
// Still 1 call left
assertEquals(1, mManager.getRemainingCallCount());
-
- // TODO Make sure pinned shortcuts won't be deleted.
}
public void testThrottling() {
final ShortcutInfo si1 = makeShortcut("shortcut1");
- assertTrue(mManager.setDynamicShortcuts(Arrays.asList(si1)));
+ assertTrue(mManager.setDynamicShortcuts(list(si1)));
assertEquals(2, mManager.getRemainingCallCount());
assertEquals(START_TIME + INTERVAL, mManager.getRateLimitResetTime());
mInjectedCurrentTimeLillis++;
- assertTrue(mManager.setDynamicShortcuts(Arrays.asList(si1)));
+ assertTrue(mManager.setDynamicShortcuts(list(si1)));
assertEquals(1, mManager.getRemainingCallCount());
assertEquals(START_TIME + INTERVAL, mManager.getRateLimitResetTime());
mInjectedCurrentTimeLillis++;
- assertTrue(mManager.setDynamicShortcuts(Arrays.asList(si1)));
+ assertTrue(mManager.setDynamicShortcuts(list(si1)));
assertEquals(0, mManager.getRemainingCallCount());
assertEquals(START_TIME + INTERVAL, mManager.getRateLimitResetTime());
// Reached the max
mInjectedCurrentTimeLillis++;
- assertFalse(mManager.setDynamicShortcuts(Arrays.asList(si1)));
+ assertFalse(mManager.setDynamicShortcuts(list(si1)));
assertEquals(0, mManager.getRemainingCallCount());
assertEquals(START_TIME + INTERVAL, mManager.getRateLimitResetTime());
// Still throttled
mInjectedCurrentTimeLillis = START_TIME + INTERVAL - 1;
- assertFalse(mManager.setDynamicShortcuts(Arrays.asList(si1)));
+ assertFalse(mManager.setDynamicShortcuts(list(si1)));
assertEquals(0, mManager.getRemainingCallCount());
assertEquals(START_TIME + INTERVAL, mManager.getRateLimitResetTime());
// Now it should work.
mInjectedCurrentTimeLillis++;
- assertTrue(mManager.setDynamicShortcuts(Arrays.asList(si1))); // fail
+ assertTrue(mManager.setDynamicShortcuts(list(si1))); // fail
assertEquals(2, mManager.getRemainingCallCount());
assertEquals(START_TIME + INTERVAL * 2, mManager.getRateLimitResetTime());
mInjectedCurrentTimeLillis++;
- assertTrue(mManager.setDynamicShortcuts(Arrays.asList(si1)));
+ assertTrue(mManager.setDynamicShortcuts(list(si1)));
assertEquals(1, mManager.getRemainingCallCount());
assertEquals(START_TIME + INTERVAL * 2, mManager.getRateLimitResetTime());
mInjectedCurrentTimeLillis++;
- assertTrue(mManager.setDynamicShortcuts(Arrays.asList(si1)));
+ assertTrue(mManager.setDynamicShortcuts(list(si1)));
assertEquals(0, mManager.getRemainingCallCount());
assertEquals(START_TIME + INTERVAL * 2, mManager.getRateLimitResetTime());
mInjectedCurrentTimeLillis++;
- assertFalse(mManager.setDynamicShortcuts(Arrays.asList(si1)));
+ assertFalse(mManager.setDynamicShortcuts(list(si1)));
assertEquals(0, mManager.getRemainingCallCount());
assertEquals(START_TIME + INTERVAL * 2, mManager.getRateLimitResetTime());
// 4 days later...
mInjectedCurrentTimeLillis = START_TIME + 4 * INTERVAL;
- assertTrue(mManager.setDynamicShortcuts(Arrays.asList(si1)));
+ assertTrue(mManager.setDynamicShortcuts(list(si1)));
assertEquals(2, mManager.getRemainingCallCount());
assertEquals(START_TIME + INTERVAL * 5, mManager.getRateLimitResetTime());
mInjectedCurrentTimeLillis++;
- assertTrue(mManager.setDynamicShortcuts(Arrays.asList(si1)));
+ assertTrue(mManager.setDynamicShortcuts(list(si1)));
assertEquals(1, mManager.getRemainingCallCount());
assertEquals(START_TIME + INTERVAL * 5, mManager.getRateLimitResetTime());
@@ -1242,7 +1575,7 @@
assertEquals(START_TIME + INTERVAL * 9, mManager.getRateLimitResetTime());
mInjectedCurrentTimeLillis++;
- assertTrue(mManager.setDynamicShortcuts(Arrays.asList(si1)));
+ assertTrue(mManager.setDynamicShortcuts(list(si1)));
assertEquals(2, mManager.getRemainingCallCount());
assertEquals(START_TIME + INTERVAL * 9, mManager.getRateLimitResetTime());
}
@@ -1250,7 +1583,7 @@
public void testThrottling_rewind() {
final ShortcutInfo si1 = makeShortcut("shortcut1");
- assertTrue(mManager.setDynamicShortcuts(Arrays.asList(si1)));
+ assertTrue(mManager.setDynamicShortcuts(list(si1)));
assertEquals(2, mManager.getRemainingCallCount());
assertEquals(START_TIME + INTERVAL, mManager.getRateLimitResetTime());
@@ -1269,7 +1602,7 @@
mInjectedCurrentTimeLillis = START_TIME - 100000;
assertEquals(3, mManager.getRemainingCallCount());
- assertTrue(mManager.setDynamicShortcuts(Arrays.asList(si1)));
+ assertTrue(mManager.setDynamicShortcuts(list(si1)));
assertEquals(2, mManager.getRemainingCallCount());
// Forward again, should be reset now.
@@ -1280,21 +1613,21 @@
public void testThrottling_perPackage() {
final ShortcutInfo si1 = makeShortcut("shortcut1");
- assertTrue(mManager.setDynamicShortcuts(Arrays.asList(si1)));
+ assertTrue(mManager.setDynamicShortcuts(list(si1)));
assertEquals(2, mManager.getRemainingCallCount());
mInjectedCurrentTimeLillis++;
- assertTrue(mManager.setDynamicShortcuts(Arrays.asList(si1)));
+ assertTrue(mManager.setDynamicShortcuts(list(si1)));
assertEquals(1, mManager.getRemainingCallCount());
mInjectedCurrentTimeLillis++;
- assertTrue(mManager.setDynamicShortcuts(Arrays.asList(si1)));
+ assertTrue(mManager.setDynamicShortcuts(list(si1)));
assertEquals(0, mManager.getRemainingCallCount());
// Reached the max
mInjectedCurrentTimeLillis++;
- assertFalse(mManager.setDynamicShortcuts(Arrays.asList(si1)));
+ assertFalse(mManager.setDynamicShortcuts(list(si1)));
// Try from a different caller.
mInjectedClientPackage = CALLING_PACKAGE_2;
@@ -1305,11 +1638,11 @@
assertEquals(3, mManager.getRemainingCallCount());
- assertTrue(mManager.setDynamicShortcuts(Arrays.asList(si2)));
+ assertTrue(mManager.setDynamicShortcuts(list(si2)));
assertEquals(2, mManager.getRemainingCallCount());
mInjectedCurrentTimeLillis++;
- assertTrue(mManager.setDynamicShortcuts(Arrays.asList(si2)));
+ assertTrue(mManager.setDynamicShortcuts(list(si2)));
assertEquals(1, mManager.getRemainingCallCount());
// Back to the original caller, still throttled.
@@ -1318,37 +1651,37 @@
mInjectedCurrentTimeLillis = START_TIME + INTERVAL - 1;
assertEquals(0, mManager.getRemainingCallCount());
- assertFalse(mManager.setDynamicShortcuts(Arrays.asList(si1)));
+ assertFalse(mManager.setDynamicShortcuts(list(si1)));
assertEquals(0, mManager.getRemainingCallCount());
// Now it should work.
mInjectedCurrentTimeLillis++;
- assertTrue(mManager.setDynamicShortcuts(Arrays.asList(si1)));
+ assertTrue(mManager.setDynamicShortcuts(list(si1)));
mInjectedCurrentTimeLillis++;
- assertTrue(mManager.setDynamicShortcuts(Arrays.asList(si1)));
+ assertTrue(mManager.setDynamicShortcuts(list(si1)));
mInjectedCurrentTimeLillis++;
- assertTrue(mManager.setDynamicShortcuts(Arrays.asList(si1)));
+ assertTrue(mManager.setDynamicShortcuts(list(si1)));
mInjectedCurrentTimeLillis++;
- assertFalse(mManager.setDynamicShortcuts(Arrays.asList(si1)));
+ assertFalse(mManager.setDynamicShortcuts(list(si1)));
mInjectedCurrentTimeLillis = START_TIME + 4 * INTERVAL;
- assertTrue(mManager.setDynamicShortcuts(Arrays.asList(si1)));
- assertTrue(mManager.setDynamicShortcuts(Arrays.asList(si1)));
- assertTrue(mManager.setDynamicShortcuts(Arrays.asList(si1)));
- assertFalse(mManager.setDynamicShortcuts(Arrays.asList(si1)));
+ assertTrue(mManager.setDynamicShortcuts(list(si1)));
+ assertTrue(mManager.setDynamicShortcuts(list(si1)));
+ assertTrue(mManager.setDynamicShortcuts(list(si1)));
+ assertFalse(mManager.setDynamicShortcuts(list(si1)));
mInjectedClientPackage = CALLING_PACKAGE_2;
mInjectedCallingUid = CALLING_UID_2;
assertEquals(3, mManager.getRemainingCallCount());
- assertTrue(mManager.setDynamicShortcuts(Arrays.asList(si2)));
- assertTrue(mManager.setDynamicShortcuts(Arrays.asList(si2)));
- assertTrue(mManager.setDynamicShortcuts(Arrays.asList(si2)));
- assertFalse(mManager.setDynamicShortcuts(Arrays.asList(si2)));
+ assertTrue(mManager.setDynamicShortcuts(list(si2)));
+ assertTrue(mManager.setDynamicShortcuts(list(si2)));
+ assertTrue(mManager.setDynamicShortcuts(list(si2)));
+ assertFalse(mManager.setDynamicShortcuts(list(si2)));
}
public void testIcons() {
@@ -1365,7 +1698,7 @@
// Set from package 1
setCaller(CALLING_PACKAGE_1);
- assertTrue(mManager.setDynamicShortcuts(Arrays.asList(
+ assertTrue(mManager.setDynamicShortcuts(list(
makeShortcutWithIcon("res32x32", res32x32),
makeShortcutWithIcon("res64x64", res64x64),
makeShortcutWithIcon("bmp32x32", bmp32x32),
@@ -1385,7 +1718,7 @@
// Call from another caller with the same ID, just to make sure storage is per-package.
setCaller(CALLING_PACKAGE_2);
- assertTrue(mManager.setDynamicShortcuts(Arrays.asList(
+ assertTrue(mManager.setDynamicShortcuts(list(
makeShortcutWithIcon("res32x32", res512x512),
makeShortcutWithIcon("res64x64", res512x512),
makeShortcutWithIcon("none", res512x512)
@@ -1403,26 +1736,25 @@
Bitmap bmp;
setCaller(LAUNCHER_1);
-
// Check hasIconResource()/hasIconFile().
assertShortcutIds(assertAllHaveIconResId(mLauncherApps.getShortcutInfo(
- CALLING_PACKAGE_1, Arrays.asList("res32x32"),
+ CALLING_PACKAGE_1, list("res32x32"),
getCallingUser())), "res32x32");
assertShortcutIds(assertAllHaveIconResId(mLauncherApps.getShortcutInfo(
- CALLING_PACKAGE_1, Arrays.asList("res64x64"), getCallingUser())),
+ CALLING_PACKAGE_1, list("res64x64"), getCallingUser())),
"res64x64");
assertShortcutIds(assertAllHaveIconFile(mLauncherApps.getShortcutInfo(
- CALLING_PACKAGE_1, Arrays.asList("bmp32x32"), getCallingUser())),
+ CALLING_PACKAGE_1, list("bmp32x32"), getCallingUser())),
"bmp32x32");
assertShortcutIds(assertAllHaveIconFile(mLauncherApps.getShortcutInfo(
- CALLING_PACKAGE_1, Arrays.asList("bmp64x64"), getCallingUser())),
+ CALLING_PACKAGE_1, list("bmp64x64"), getCallingUser())),
"bmp64x64");
assertShortcutIds(assertAllHaveIconFile(mLauncherApps.getShortcutInfo(
- CALLING_PACKAGE_1, Arrays.asList("bmp512x512"), getCallingUser())),
+ CALLING_PACKAGE_1, list("bmp512x512"), getCallingUser())),
"bmp512x512");
// Check
@@ -1517,7 +1849,7 @@
final File p11_1_3 = openIconFileForWriteAndGetPath(11, CALLING_PACKAGE_1);
// Make sure their paths are all unique
- assertAllUnique(Arrays.asList(
+ assertAllUnique(list(
p10_1_1,
p10_1_2,
p10_1_3,
@@ -1546,7 +1878,7 @@
assertEquals(p11_1_1.getParent(), p11_1_3.getParent());
// Check the parents are still unique.
- assertAllUnique(Arrays.asList(
+ assertAllUnique(list(
p10_1_1.getParent(),
p10_2_1.getParent(),
p11_1_1.getParent()
@@ -1571,7 +1903,7 @@
public void testUpdateShortcuts() {
runWithCaller(CALLING_PACKAGE_1, UserHandle.USER_SYSTEM, () -> {
- assertTrue(mManager.setDynamicShortcuts(Arrays.asList(
+ assertTrue(mManager.setDynamicShortcuts(list(
makeShortcut("s1"),
makeShortcut("s2"),
makeShortcut("s3"),
@@ -1580,7 +1912,7 @@
)));
});
runWithCaller(CALLING_PACKAGE_2, UserHandle.USER_SYSTEM, () -> {
- assertTrue(mManager.setDynamicShortcuts(Arrays.asList(
+ assertTrue(mManager.setDynamicShortcuts(list(
makeShortcut("s1"),
makeShortcut("s2"),
makeShortcut("s3"),
@@ -1589,9 +1921,9 @@
)));
});
runWithCaller(LAUNCHER_1, UserHandle.USER_SYSTEM, () -> {
- mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, Arrays.asList("s2", "s3"),
+ mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s2", "s3"),
getCallingUser());
- mLauncherApps.pinShortcuts(CALLING_PACKAGE_2, Arrays.asList("s4", "s5"),
+ mLauncherApps.pinShortcuts(CALLING_PACKAGE_2, list("s4", "s5"),
getCallingUser());
});
runWithCaller(CALLING_PACKAGE_1, UserHandle.USER_SYSTEM, () -> {
@@ -1631,7 +1963,7 @@
.setTitle("new title")
.build();
- mManager.updateShortcuts(Arrays.asList(s2, s4));
+ mManager.updateShortcuts(list(s2, s4));
});
runWithCaller(CALLING_PACKAGE_2, UserHandle.USER_SYSTEM, () -> {
ShortcutInfo s2 = makeShortcutBuilder()
@@ -1645,7 +1977,7 @@
.setIntent(new Intent(Intent.ACTION_ALL_APPS))
.build();
- mManager.updateShortcuts(Arrays.asList(s2, s4));
+ mManager.updateShortcuts(list(s2, s4));
});
runWithCaller(CALLING_PACKAGE_1, UserHandle.USER_SYSTEM, () -> {
@@ -1691,10 +2023,11 @@
// TODO Check with other fields too.
// TODO Check bitmap removal too.
- }
- // TODO: updateShortcuts()
- // TODO: getPinnedShortcuts()
+ runWithCaller(CALLING_PACKAGE_2, USER_11, () -> {
+ mManager.updateShortcuts(list());
+ });
+ }
// === Test for launcher side APIs ===
@@ -1709,6 +2042,20 @@
return q;
}
+ private static ShortcutQuery buildAllQuery(String packageName) {
+ final ShortcutQuery q = new ShortcutQuery();
+ q.setPackage(packageName);
+ q.setQueryFlags(ShortcutQuery.FLAG_GET_DYNAMIC | ShortcutQuery.FLAG_GET_PINNED);
+ return q;
+ }
+
+ private static ShortcutQuery buildPinnedQuery(String packageName) {
+ final ShortcutQuery q = new ShortcutQuery();
+ q.setPackage(packageName);
+ q.setQueryFlags(ShortcutQuery.FLAG_GET_PINNED);
+ return q;
+ }
+
public void testGetShortcuts() {
// Set up shortcuts.
@@ -1717,17 +2064,17 @@
final ShortcutInfo s1_1 = makeShortcutWithTimestamp("s1", 5000);
final ShortcutInfo s1_2 = makeShortcutWithTimestamp("s2", 1000);
- assertTrue(mManager.setDynamicShortcuts(Arrays.asList(s1_1, s1_2)));
+ assertTrue(mManager.setDynamicShortcuts(list(s1_1, s1_2)));
setCaller(CALLING_PACKAGE_2);
final ShortcutInfo s2_2 = makeShortcutWithTimestamp("s2", 1500);
final ShortcutInfo s2_3 = makeShortcutWithTimestamp("s3", 3000);
final ShortcutInfo s2_4 = makeShortcutWithTimestamp("s4", 500);
- assertTrue(mManager.setDynamicShortcuts(Arrays.asList(s2_2, s2_3, s2_4)));
+ assertTrue(mManager.setDynamicShortcuts(list(s2_2, s2_3, s2_4)));
setCaller(CALLING_PACKAGE_3);
- final ShortcutInfo s3_2 = makeShortcutWithTimestamp("s3", 5000);
- assertTrue(mManager.setDynamicShortcuts(Arrays.asList(s3_2)));
+ final ShortcutInfo s3_2 = makeShortcutWithTimestamp("s3", START_TIME + 5000);
+ assertTrue(mManager.setDynamicShortcuts(list(s3_2)));
setCaller(LAUNCHER_1);
@@ -1765,7 +2112,7 @@
// Pin some shortcuts.
mLauncherApps.pinShortcuts(CALLING_PACKAGE_2,
- Arrays.asList("s3", "s4"), getCallingUser());
+ list("s3", "s4"), getCallingUser());
// Pinned ones only
assertAllPinned(assertAllHaveTitle(assertAllNotHaveIntents(assertShortcutIds(
@@ -1808,7 +2155,7 @@
makeIntent(Intent.ACTION_ASSIST, ShortcutActivity3.class),
/* weight */ 12);
- assertTrue(mManager.setDynamicShortcuts(Arrays.asList(s1_1, s1_2)));
+ assertTrue(mManager.setDynamicShortcuts(list(s1_1, s1_2)));
dumpsysOnLogcat();
setCaller(CALLING_PACKAGE_2);
@@ -1820,14 +2167,14 @@
makeIntent(Intent.ACTION_ANSWER, ShortcutActivity2.class,
"key1", "val1", "nest", makeBundle("key", 123)),
/* weight */ 10);
- assertTrue(mManager.setDynamicShortcuts(Arrays.asList(s2_1)));
+ assertTrue(mManager.setDynamicShortcuts(list(s2_1)));
dumpsysOnLogcat();
// Pin some.
setCaller(LAUNCHER_1);
mLauncherApps.pinShortcuts(CALLING_PACKAGE_1,
- Arrays.asList("s2"), getCallingUser());
+ list("s2"), getCallingUser());
dumpsysOnLogcat();
@@ -1846,19 +2193,19 @@
list = assertShortcutIds(assertAllHaveTitle(assertAllNotHaveIntents(
assertAllNotKeyFieldsOnly(
mLauncherApps.getShortcutInfo(CALLING_PACKAGE_1,
- Arrays.asList("s2", "s1", "s3", null), getCallingUser())))),
+ list("s2", "s1", "s3", null), getCallingUser())))),
"s1", "s2");
assertEquals("Title 1", findById(list, "s1").getTitle());
assertEquals("Title 2", findById(list, "s2").getTitle());
assertShortcutIds(assertAllHaveTitle(assertAllNotHaveIntents(
mLauncherApps.getShortcutInfo(CALLING_PACKAGE_1,
- Arrays.asList("s3"), getCallingUser())))
+ list("s3"), getCallingUser())))
/* none */);
list = assertShortcutIds(assertAllHaveTitle(assertAllNotHaveIntents(
mLauncherApps.getShortcutInfo(CALLING_PACKAGE_2,
- Arrays.asList("s1", "s2", "s3"), getCallingUser()))),
+ list("s1", "s2", "s3"), getCallingUser()))),
"s1");
assertEquals("ABC", findById(list, "s1").getTitle());
}
@@ -1869,31 +2216,31 @@
final ShortcutInfo s1_1 = makeShortcutWithTimestamp("s1", 1000);
final ShortcutInfo s1_2 = makeShortcutWithTimestamp("s2", 2000);
- assertTrue(mManager.setDynamicShortcuts(Arrays.asList(s1_1, s1_2)));
+ assertTrue(mManager.setDynamicShortcuts(list(s1_1, s1_2)));
});
runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
final ShortcutInfo s2_2 = makeShortcutWithTimestamp("s2", 1500);
final ShortcutInfo s2_3 = makeShortcutWithTimestamp("s3", 3000);
final ShortcutInfo s2_4 = makeShortcutWithTimestamp("s4", 500);
- assertTrue(mManager.setDynamicShortcuts(Arrays.asList(s2_2, s2_3, s2_4)));
+ assertTrue(mManager.setDynamicShortcuts(list(s2_2, s2_3, s2_4)));
});
runWithCaller(CALLING_PACKAGE_3, USER_0, () -> {
final ShortcutInfo s3_2 = makeShortcutWithTimestamp("s2", 1000);
- assertTrue(mManager.setDynamicShortcuts(Arrays.asList(s3_2)));
+ assertTrue(mManager.setDynamicShortcuts(list(s3_2)));
});
// Pin some.
runWithCaller(LAUNCHER_1, USER_0, () -> {
mLauncherApps.pinShortcuts(CALLING_PACKAGE_1,
- Arrays.asList("s2", "s3"), getCallingUser());
+ list("s2", "s3"), getCallingUser());
mLauncherApps.pinShortcuts(CALLING_PACKAGE_2,
- Arrays.asList("s3", "s4", "s5"), getCallingUser());
+ list("s3", "s4", "s5"), getCallingUser());
mLauncherApps.pinShortcuts(CALLING_PACKAGE_3,
- Arrays.asList("s3"), getCallingUser()); // Note ID doesn't exist
+ list("s3"), getCallingUser()); // Note ID doesn't exist
});
// Delete some.
@@ -1938,12 +2285,12 @@
public void testPinShortcutAndGetPinnedShortcuts_multi() {
// Create some shortcuts.
runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
- assertTrue(mManager.setDynamicShortcuts(Arrays.asList(
+ assertTrue(mManager.setDynamicShortcuts(list(
makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"))));
});
runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
- assertTrue(mManager.setDynamicShortcuts(Arrays.asList(
+ assertTrue(mManager.setDynamicShortcuts(list(
makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"))));
});
@@ -1952,10 +2299,10 @@
// Pin some.
runWithCaller(LAUNCHER_1, USER_0, () -> {
mLauncherApps.pinShortcuts(CALLING_PACKAGE_1,
- Arrays.asList("s3", "s4"), getCallingUser());
+ list("s3", "s4"), getCallingUser());
mLauncherApps.pinShortcuts(CALLING_PACKAGE_2,
- Arrays.asList("s1", "s2", "s4"), getCallingUser());
+ list("s1", "s2", "s4"), getCallingUser());
});
dumpsysOnLogcat();
@@ -2029,10 +2376,10 @@
// Now pin some.
mLauncherApps.pinShortcuts(CALLING_PACKAGE_1,
- Arrays.asList("s1", "s2"), getCallingUser());
+ list("s1", "s2"), getCallingUser());
mLauncherApps.pinShortcuts(CALLING_PACKAGE_2,
- Arrays.asList("s1", "s2"), getCallingUser());
+ list("s1", "s2"), getCallingUser());
assertShortcutIds(assertAllDynamic(
mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
@@ -2052,6 +2399,10 @@
mService.saveDirtyInfo();
initService();
+ // Load from file.
+ mService.handleUnlockUser(USER_0);
+
+ // Make sure package info is restored too.
runWithCaller(LAUNCHER_1, USER_0, () -> {
assertShortcutIds(assertAllPinned(assertAllNotKeyFieldsOnly(
mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
@@ -2108,7 +2459,7 @@
// Update pined. Note s2 and s3 are actually available, but not visible to this
// launcher, so still can't be pinned.
- mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, Arrays.asList("s1", "s2", "s3", "s4"),
+ mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s1", "s2", "s3", "s4"),
getCallingUser());
assertShortcutIds(assertAllPinned(assertAllNotKeyFieldsOnly(
@@ -2130,7 +2481,7 @@
"s3");
// Now "s1" is visible, so can be pinned.
- mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, Arrays.asList("s1", "s2", "s3", "s4"),
+ mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s1", "s2", "s3", "s4"),
getCallingUser());
assertShortcutIds(assertAllPinned(assertAllNotKeyFieldsOnly(
@@ -2141,8 +2492,8 @@
// Now clear pinned shortcuts. First, from launcher 1.
runWithCaller(LAUNCHER_1, USER_0, () -> {
- mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, Arrays.asList(), getCallingUser());
- mLauncherApps.pinShortcuts(CALLING_PACKAGE_2, Arrays.asList(), getCallingUser());
+ mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list(), getCallingUser());
+ mLauncherApps.pinShortcuts(CALLING_PACKAGE_2, list(), getCallingUser());
assertEquals(0,
mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
@@ -2162,8 +2513,8 @@
// Clear all pins from launcher 2.
runWithCaller(LAUNCHER_2, USER_0, () -> {
- mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, Arrays.asList(), getCallingUser());
- mLauncherApps.pinShortcuts(CALLING_PACKAGE_2, Arrays.asList(), getCallingUser());
+ mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list(), getCallingUser());
+ mLauncherApps.pinShortcuts(CALLING_PACKAGE_2, list(), getCallingUser());
assertEquals(0,
mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
@@ -2182,7 +2533,502 @@
});
}
- public void testCreateShortcutIntent() {
+ public void testPinShortcutAndGetPinnedShortcuts_crossProfile_plusLaunch() {
+ // Create some shortcuts.
+ runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+ assertTrue(mManager.setDynamicShortcuts(list(
+ makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"))));
+ });
+ runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
+ assertTrue(mManager.setDynamicShortcuts(list(
+ makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"))));
+ });
+ runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
+ assertTrue(mManager.setDynamicShortcuts(list(
+ makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"),
+ makeShortcut("s4"), makeShortcut("s5"), makeShortcut("s6"))));
+ });
+
+ // Pin some shortcuts and see the result.
+
+ runWithCaller(LAUNCHER_1, USER_0, () -> {
+ mLauncherApps.pinShortcuts(CALLING_PACKAGE_1,
+ list("s1"), HANDLE_USER_0);
+
+ mLauncherApps.pinShortcuts(CALLING_PACKAGE_2,
+ list("s1", "s2", "s3"), HANDLE_USER_0);
+ });
+
+ runWithCaller(LAUNCHER_1, USER_P0, () -> {
+ mLauncherApps.pinShortcuts(CALLING_PACKAGE_1,
+ list("s2"), HANDLE_USER_0);
+
+ mLauncherApps.pinShortcuts(CALLING_PACKAGE_2,
+ list("s2", "s3"), HANDLE_USER_0);
+ });
+
+ runWithCaller(LAUNCHER_2, USER_P0, () -> {
+ mLauncherApps.pinShortcuts(CALLING_PACKAGE_1,
+ list("s3"), HANDLE_USER_0);
+
+ mLauncherApps.pinShortcuts(CALLING_PACKAGE_2,
+ list("s3"), HANDLE_USER_0);
+ });
+
+ runWithCaller(LAUNCHER_2, USER_10, () -> {
+ mLauncherApps.pinShortcuts(CALLING_PACKAGE_1,
+ list("s1", "s2", "s3"), HANDLE_USER_10);
+ });
+
+ // Cross profile pinning.
+ final int PIN_AND_DYNAMIC = ShortcutQuery.FLAG_GET_PINNED | ShortcutQuery.FLAG_GET_DYNAMIC;
+
+ runWithCaller(LAUNCHER_1, USER_0, () -> {
+ assertShortcutIds(assertAllPinned(
+ mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
+ /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), HANDLE_USER_0)),
+ "s1");
+ assertShortcutIds(assertAllDynamic(
+ mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
+ /* activity =*/ null, ShortcutQuery.FLAG_GET_DYNAMIC), HANDLE_USER_0)),
+ "s1", "s2", "s3");
+ assertShortcutIds(assertAllDynamicOrPinned(
+ mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
+ /* activity =*/ null, PIN_AND_DYNAMIC), HANDLE_USER_0)),
+ "s1", "s2", "s3");
+
+ assertShortcutIds(assertAllPinned(
+ mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
+ /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), HANDLE_USER_0)),
+ "s1", "s2", "s3");
+ assertShortcutIds(assertAllDynamic(
+ mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
+ /* activity =*/ null, ShortcutQuery.FLAG_GET_DYNAMIC), HANDLE_USER_0)),
+ "s1", "s2", "s3");
+ assertShortcutIds(assertAllDynamicOrPinned(
+ mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
+ /* activity =*/ null, PIN_AND_DYNAMIC), HANDLE_USER_0)),
+ "s1", "s2", "s3");
+
+ assertShortcutLaunchable(CALLING_PACKAGE_1, "s1", USER_0);
+ assertShortcutLaunchable(CALLING_PACKAGE_1, "s2", USER_0);
+ assertShortcutLaunchable(CALLING_PACKAGE_1, "s3", USER_0);
+
+ assertShortcutLaunchable(CALLING_PACKAGE_2, "s1", USER_0);
+ assertShortcutLaunchable(CALLING_PACKAGE_2, "s2", USER_0);
+ assertShortcutLaunchable(CALLING_PACKAGE_2, "s3", USER_0);
+
+ assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s1", USER_10);
+ assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s2", USER_10);
+ assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s3", USER_10);
+ assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s4", USER_10);
+ assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s5", USER_10);
+ assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s6", USER_10);
+ });
+ runWithCaller(LAUNCHER_1, USER_P0, () -> {
+ assertShortcutIds(assertAllPinned(
+ mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
+ /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), HANDLE_USER_0)),
+ "s2");
+ assertShortcutIds(assertAllDynamic(
+ mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
+ /* activity =*/ null, ShortcutQuery.FLAG_GET_DYNAMIC), HANDLE_USER_0)),
+ "s1", "s2", "s3");
+ assertShortcutIds(assertAllDynamicOrPinned(
+ mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
+ /* activity =*/ null, PIN_AND_DYNAMIC), HANDLE_USER_0)),
+ "s1", "s2", "s3");
+
+ assertShortcutIds(assertAllPinned(
+ mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
+ /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), HANDLE_USER_0)),
+ "s2", "s3");
+ assertShortcutIds(assertAllDynamic(
+ mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
+ /* activity =*/ null, ShortcutQuery.FLAG_GET_DYNAMIC), HANDLE_USER_0)),
+ "s1", "s2", "s3");
+ assertShortcutIds(assertAllDynamicOrPinned(
+ mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
+ /* activity =*/ null, PIN_AND_DYNAMIC), HANDLE_USER_0)),
+ "s1", "s2", "s3");
+
+ assertShortcutLaunchable(CALLING_PACKAGE_1, "s1", USER_0);
+ assertShortcutLaunchable(CALLING_PACKAGE_1, "s2", USER_0);
+ assertShortcutLaunchable(CALLING_PACKAGE_1, "s3", USER_0);
+
+ assertShortcutLaunchable(CALLING_PACKAGE_2, "s1", USER_0);
+ assertShortcutLaunchable(CALLING_PACKAGE_2, "s2", USER_0);
+ assertShortcutLaunchable(CALLING_PACKAGE_2, "s3", USER_0);
+
+ assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s1", USER_10);
+ assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s2", USER_10);
+ assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s3", USER_10);
+ assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s4", USER_10);
+ assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s5", USER_10);
+ assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s6", USER_10);
+ });
+ runWithCaller(LAUNCHER_2, USER_P0, () -> {
+ assertShortcutIds(assertAllPinned(
+ mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
+ /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), HANDLE_USER_0)),
+ "s3");
+ assertShortcutIds(assertAllDynamic(
+ mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
+ /* activity =*/ null, ShortcutQuery.FLAG_GET_DYNAMIC), HANDLE_USER_0)),
+ "s1", "s2", "s3");
+ assertShortcutIds(assertAllDynamicOrPinned(
+ mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
+ /* activity =*/ null, PIN_AND_DYNAMIC), HANDLE_USER_0)),
+ "s1", "s2", "s3");
+
+ assertShortcutIds(assertAllPinned(
+ mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
+ /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), HANDLE_USER_0)),
+ "s3");
+ assertShortcutIds(assertAllDynamic(
+ mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
+ /* activity =*/ null, ShortcutQuery.FLAG_GET_DYNAMIC), HANDLE_USER_0)),
+ "s1", "s2", "s3");
+ assertShortcutIds(assertAllDynamicOrPinned(
+ mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
+ /* activity =*/ null, PIN_AND_DYNAMIC), HANDLE_USER_0)),
+ "s1", "s2", "s3");
+
+ assertShortcutLaunchable(CALLING_PACKAGE_1, "s1", USER_0);
+ assertShortcutLaunchable(CALLING_PACKAGE_1, "s2", USER_0);
+ assertShortcutLaunchable(CALLING_PACKAGE_1, "s3", USER_0);
+
+ assertShortcutLaunchable(CALLING_PACKAGE_2, "s1", USER_0);
+ assertShortcutLaunchable(CALLING_PACKAGE_2, "s2", USER_0);
+ assertShortcutLaunchable(CALLING_PACKAGE_2, "s3", USER_0);
+
+ assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s1", USER_10);
+ assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s2", USER_10);
+ assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s3", USER_10);
+ assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s4", USER_10);
+ assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s5", USER_10);
+ assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s6", USER_10);
+ });
+ runWithCaller(LAUNCHER_2, USER_10, () -> {
+ assertShortcutIds(assertAllPinned(
+ mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
+ /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), HANDLE_USER_10)),
+ "s1", "s2", "s3");
+ assertShortcutIds(assertAllDynamic(
+ mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
+ /* activity =*/ null, ShortcutQuery.FLAG_GET_DYNAMIC), HANDLE_USER_10)),
+ "s1", "s2", "s3", "s4", "s5", "s6");
+ assertShortcutIds(assertAllDynamicOrPinned(
+ mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
+ /* activity =*/ null, PIN_AND_DYNAMIC), HANDLE_USER_10)),
+ "s1", "s2", "s3", "s4", "s5", "s6");
+ });
+
+ // Remove some dynamic shortcuts.
+
+ runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+ assertTrue(mManager.setDynamicShortcuts(list(
+ makeShortcut("s1"))));
+ });
+ runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
+ assertTrue(mManager.setDynamicShortcuts(list(
+ makeShortcut("s1"))));
+ });
+ runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
+ assertTrue(mManager.setDynamicShortcuts(list(
+ makeShortcut("s1"))));
+ });
+
+ runWithCaller(LAUNCHER_1, USER_0, () -> {
+ assertShortcutIds(assertAllPinned(
+ mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
+ /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), HANDLE_USER_0)),
+ "s1");
+ assertShortcutIds(assertAllDynamic(
+ mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
+ /* activity =*/ null, ShortcutQuery.FLAG_GET_DYNAMIC), HANDLE_USER_0)),
+ "s1");
+ assertShortcutIds(assertAllDynamicOrPinned(
+ mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
+ /* activity =*/ null, PIN_AND_DYNAMIC), HANDLE_USER_0)),
+ "s1");
+
+ assertShortcutIds(assertAllPinned(
+ mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
+ /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), HANDLE_USER_0)),
+ "s1", "s2", "s3");
+ assertShortcutIds(assertAllDynamic(
+ mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
+ /* activity =*/ null, ShortcutQuery.FLAG_GET_DYNAMIC), HANDLE_USER_0)),
+ "s1");
+ assertShortcutIds(assertAllDynamicOrPinned(
+ mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
+ /* activity =*/ null, PIN_AND_DYNAMIC), HANDLE_USER_0)),
+ "s1", "s2", "s3");
+
+ assertShortcutLaunchable(CALLING_PACKAGE_1, "s1", USER_0);
+ assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s2", USER_0);
+ assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s3", USER_0);
+
+ assertShortcutLaunchable(CALLING_PACKAGE_2, "s1", USER_0);
+ assertShortcutLaunchable(CALLING_PACKAGE_2, "s2", USER_0);
+ assertShortcutLaunchable(CALLING_PACKAGE_2, "s3", USER_0);
+
+ assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s1", USER_10);
+ assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s2", USER_10);
+ assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s3", USER_10);
+ assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s4", USER_10);
+ assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s5", USER_10);
+ assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s6", USER_10);
+ });
+ runWithCaller(LAUNCHER_1, USER_P0, () -> {
+ assertShortcutIds(assertAllPinned(
+ mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
+ /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), HANDLE_USER_0)),
+ "s2");
+ assertShortcutIds(assertAllDynamic(
+ mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
+ /* activity =*/ null, ShortcutQuery.FLAG_GET_DYNAMIC), HANDLE_USER_0)),
+ "s1");
+ assertShortcutIds(assertAllDynamicOrPinned(
+ mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
+ /* activity =*/ null, PIN_AND_DYNAMIC), HANDLE_USER_0)),
+ "s1", "s2");
+
+ assertShortcutIds(assertAllPinned(
+ mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
+ /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), HANDLE_USER_0)),
+ "s2", "s3");
+ assertShortcutIds(assertAllDynamic(
+ mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
+ /* activity =*/ null, ShortcutQuery.FLAG_GET_DYNAMIC), HANDLE_USER_0)),
+ "s1");
+ assertShortcutIds(assertAllDynamicOrPinned(
+ mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
+ /* activity =*/ null, PIN_AND_DYNAMIC), HANDLE_USER_0)),
+ "s1", "s2", "s3");
+
+ assertShortcutLaunchable(CALLING_PACKAGE_1, "s1", USER_0);
+ assertShortcutLaunchable(CALLING_PACKAGE_1, "s2", USER_0);
+ assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s3", USER_0);
+
+ assertShortcutLaunchable(CALLING_PACKAGE_2, "s1", USER_0);
+ assertShortcutLaunchable(CALLING_PACKAGE_2, "s2", USER_0);
+ assertShortcutLaunchable(CALLING_PACKAGE_2, "s3", USER_0);
+
+ assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s1", USER_10);
+ assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s2", USER_10);
+ assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s3", USER_10);
+ assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s4", USER_10);
+ assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s5", USER_10);
+ assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s6", USER_10);
+ });
+ runWithCaller(LAUNCHER_2, USER_P0, () -> {
+ assertShortcutIds(assertAllPinned(
+ mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
+ /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), HANDLE_USER_0)),
+ "s3");
+ assertShortcutIds(assertAllDynamic(
+ mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
+ /* activity =*/ null, ShortcutQuery.FLAG_GET_DYNAMIC), HANDLE_USER_0)),
+ "s1");
+ assertShortcutIds(assertAllDynamicOrPinned(
+ mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
+ /* activity =*/ null, PIN_AND_DYNAMIC), HANDLE_USER_0)),
+ "s1", "s3");
+
+ assertShortcutIds(assertAllPinned(
+ mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
+ /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), HANDLE_USER_0)),
+ "s3");
+ assertShortcutIds(assertAllDynamic(
+ mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
+ /* activity =*/ null, ShortcutQuery.FLAG_GET_DYNAMIC), HANDLE_USER_0)),
+ "s1");
+ assertShortcutIds(assertAllDynamicOrPinned(
+ mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
+ /* activity =*/ null, PIN_AND_DYNAMIC), HANDLE_USER_0)),
+ "s1", "s3");
+
+ assertShortcutLaunchable(CALLING_PACKAGE_1, "s1", USER_0);
+ assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s2", USER_0);
+ assertShortcutLaunchable(CALLING_PACKAGE_1, "s3", USER_0);
+
+ assertShortcutLaunchable(CALLING_PACKAGE_2, "s1", USER_0);
+ assertShortcutNotLaunchable(CALLING_PACKAGE_2, "s2", USER_0);
+ assertShortcutLaunchable(CALLING_PACKAGE_2, "s3", USER_0);
+
+ assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s1", USER_10);
+ assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s2", USER_10);
+ assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s3", USER_10);
+ assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s4", USER_10);
+ assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s5", USER_10);
+ assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s6", USER_10);
+ });
+ runWithCaller(LAUNCHER_2, USER_10, () -> {
+ assertShortcutIds(assertAllPinned(
+ mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
+ /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), HANDLE_USER_10)),
+ "s1", "s2", "s3");
+ assertShortcutIds(assertAllDynamic(
+ mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
+ /* activity =*/ null, ShortcutQuery.FLAG_GET_DYNAMIC), HANDLE_USER_10)),
+ "s1");
+ assertShortcutIds(assertAllDynamicOrPinned(
+ mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
+ /* activity =*/ null, PIN_AND_DYNAMIC), HANDLE_USER_10)),
+ "s1", "s2", "s3");
+
+ assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s1", USER_0);
+ assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s2", USER_0);
+ assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s3", USER_0);
+
+ assertShortcutNotLaunchable(CALLING_PACKAGE_2, "s1", USER_0);
+ assertShortcutNotLaunchable(CALLING_PACKAGE_2, "s2", USER_0);
+ assertShortcutNotLaunchable(CALLING_PACKAGE_2, "s3", USER_0);
+
+ assertShortcutLaunchable(CALLING_PACKAGE_1, "s1", USER_10);
+ assertShortcutLaunchable(CALLING_PACKAGE_1, "s2", USER_10);
+ assertShortcutLaunchable(CALLING_PACKAGE_1, "s3", USER_10);
+ assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s4", USER_10);
+ assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s5", USER_10);
+ assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s6", USER_10);
+ });
+
+ // Save & load and make sure we still have the same information.
+ mService.saveDirtyInfo();
+ initService();
+ mService.handleUnlockUser(USER_0);
+
+ runWithCaller(LAUNCHER_1, USER_0, () -> {
+ assertShortcutIds(assertAllPinned(
+ mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
+ /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), HANDLE_USER_0)),
+ "s1");
+ assertShortcutIds(assertAllDynamic(
+ mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
+ /* activity =*/ null, ShortcutQuery.FLAG_GET_DYNAMIC), HANDLE_USER_0)),
+ "s1");
+ assertShortcutIds(assertAllDynamicOrPinned(
+ mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
+ /* activity =*/ null, PIN_AND_DYNAMIC), HANDLE_USER_0)),
+ "s1");
+
+ assertShortcutIds(assertAllPinned(
+ mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
+ /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), HANDLE_USER_0)),
+ "s1", "s2", "s3");
+ assertShortcutIds(assertAllDynamic(
+ mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
+ /* activity =*/ null, ShortcutQuery.FLAG_GET_DYNAMIC), HANDLE_USER_0)),
+ "s1");
+ assertShortcutIds(assertAllDynamicOrPinned(
+ mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
+ /* activity =*/ null, PIN_AND_DYNAMIC), HANDLE_USER_0)),
+ "s1", "s2", "s3");
+
+ assertShortcutLaunchable(CALLING_PACKAGE_1, "s1", USER_0);
+ assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s2", USER_0);
+ assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s3", USER_0);
+
+ assertShortcutLaunchable(CALLING_PACKAGE_2, "s1", USER_0);
+ assertShortcutLaunchable(CALLING_PACKAGE_2, "s2", USER_0);
+ assertShortcutLaunchable(CALLING_PACKAGE_2, "s3", USER_0);
+
+ assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s1", USER_10);
+ assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s2", USER_10);
+ assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s3", USER_10);
+ assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s4", USER_10);
+ assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s5", USER_10);
+ assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s6", USER_10);
+ });
+ runWithCaller(LAUNCHER_1, USER_P0, () -> {
+ assertShortcutIds(assertAllPinned(
+ mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
+ /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), HANDLE_USER_0)),
+ "s2");
+ assertShortcutIds(assertAllDynamic(
+ mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
+ /* activity =*/ null, ShortcutQuery.FLAG_GET_DYNAMIC), HANDLE_USER_0)),
+ "s1");
+ assertShortcutIds(assertAllDynamicOrPinned(
+ mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
+ /* activity =*/ null, PIN_AND_DYNAMIC), HANDLE_USER_0)),
+ "s1", "s2");
+
+ assertShortcutIds(assertAllPinned(
+ mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
+ /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), HANDLE_USER_0)),
+ "s2", "s3");
+ assertShortcutIds(assertAllDynamic(
+ mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
+ /* activity =*/ null, ShortcutQuery.FLAG_GET_DYNAMIC), HANDLE_USER_0)),
+ "s1");
+ assertShortcutIds(assertAllDynamicOrPinned(
+ mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
+ /* activity =*/ null, PIN_AND_DYNAMIC), HANDLE_USER_0)),
+ "s1", "s2", "s3");
+
+ assertShortcutLaunchable(CALLING_PACKAGE_1, "s1", USER_0);
+ assertShortcutLaunchable(CALLING_PACKAGE_1, "s2", USER_0);
+ assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s3", USER_0);
+
+ assertShortcutLaunchable(CALLING_PACKAGE_2, "s1", USER_0);
+ assertShortcutLaunchable(CALLING_PACKAGE_2, "s2", USER_0);
+ assertShortcutLaunchable(CALLING_PACKAGE_2, "s3", USER_0);
+
+ assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s1", USER_10);
+ assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s2", USER_10);
+ assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s3", USER_10);
+ assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s4", USER_10);
+ assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s5", USER_10);
+ assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s6", USER_10);
+ });
+ runWithCaller(LAUNCHER_2, USER_P0, () -> {
+ assertShortcutIds(assertAllPinned(
+ mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
+ /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), HANDLE_USER_0)),
+ "s3");
+ assertShortcutIds(assertAllDynamic(
+ mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
+ /* activity =*/ null, ShortcutQuery.FLAG_GET_DYNAMIC), HANDLE_USER_0)),
+ "s1");
+ assertShortcutIds(assertAllDynamicOrPinned(
+ mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
+ /* activity =*/ null, PIN_AND_DYNAMIC), HANDLE_USER_0)),
+ "s1", "s3");
+
+ assertShortcutIds(assertAllPinned(
+ mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
+ /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), HANDLE_USER_0)),
+ "s3");
+ assertShortcutIds(assertAllDynamic(
+ mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
+ /* activity =*/ null, ShortcutQuery.FLAG_GET_DYNAMIC), HANDLE_USER_0)),
+ "s1");
+ assertShortcutIds(assertAllDynamicOrPinned(
+ mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
+ /* activity =*/ null, PIN_AND_DYNAMIC), HANDLE_USER_0)),
+ "s1", "s3");
+
+ assertShortcutLaunchable(CALLING_PACKAGE_1, "s1", USER_0);
+ assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s2", USER_0);
+ assertShortcutLaunchable(CALLING_PACKAGE_1, "s3", USER_0);
+
+ assertShortcutLaunchable(CALLING_PACKAGE_2, "s1", USER_0);
+ assertShortcutNotLaunchable(CALLING_PACKAGE_2, "s2", USER_0);
+ assertShortcutLaunchable(CALLING_PACKAGE_2, "s3", USER_0);
+
+ assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s1", USER_10);
+ assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s2", USER_10);
+ assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s3", USER_10);
+ assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s4", USER_10);
+ assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s5", USER_10);
+ assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s6", USER_10);
+ });
+ }
+
+ public void testStartShortcut() {
// Create some shortcuts.
setCaller(CALLING_PACKAGE_1);
final ShortcutInfo s1_1 = makeShortcut(
@@ -2202,7 +3048,7 @@
makeIntent(Intent.ACTION_ASSIST, ShortcutActivity3.class),
/* weight */ 12);
- assertTrue(mManager.setDynamicShortcuts(Arrays.asList(s1_1, s1_2)));
+ assertTrue(mManager.setDynamicShortcuts(list(s1_1, s1_2)));
setCaller(CALLING_PACKAGE_2);
final ShortcutInfo s2_1 = makeShortcut(
@@ -2213,15 +3059,15 @@
makeIntent(Intent.ACTION_ANSWER, ShortcutActivity.class,
"key1", "val1", "nest", makeBundle("key", 123)),
/* weight */ 10);
- assertTrue(mManager.setDynamicShortcuts(Arrays.asList(s2_1)));
+ assertTrue(mManager.setDynamicShortcuts(list(s2_1)));
// Pin all.
setCaller(LAUNCHER_1);
mLauncherApps.pinShortcuts(CALLING_PACKAGE_1,
- Arrays.asList("s1", "s2"), getCallingUser());
+ list("s1", "s2"), getCallingUser());
mLauncherApps.pinShortcuts(CALLING_PACKAGE_2,
- Arrays.asList("s1"), getCallingUser());
+ list("s1"), getCallingUser());
// Just to make it complicated, delete some.
setCaller(CALLING_PACKAGE_1);
@@ -2229,29 +3075,22 @@
// intent and check.
setCaller(LAUNCHER_1);
+
Intent intent;
- intent = mInternal.createShortcutIntent(getCallingPackage(),
- CALLING_PACKAGE_1, "s1", getCallingUserId());
+ intent = launchShortcutAndGetIntent(CALLING_PACKAGE_1, "s1", USER_0);
assertEquals(ShortcutActivity2.class.getName(), intent.getComponent().getClassName());
- intent = mInternal.createShortcutIntent(getCallingPackage(),
- CALLING_PACKAGE_1, "s2", getCallingUserId());
+
+ intent = launchShortcutAndGetIntent(CALLING_PACKAGE_1, "s2", USER_0);
assertEquals(ShortcutActivity3.class.getName(), intent.getComponent().getClassName());
- intent = mInternal.createShortcutIntent(getCallingPackage(),
- CALLING_PACKAGE_2, "s1", getCallingUserId());
+ intent = launchShortcutAndGetIntent(CALLING_PACKAGE_2, "s1", USER_0);
assertEquals(ShortcutActivity.class.getName(), intent.getComponent().getClassName());
// TODO Check extra, etc
}
public void testLauncherCallback() throws Throwable {
-
- // TODO Add "multi" version -- run the test with two launchers and make sure the callback
- // argument only contains the ones that are actually visible to each launcher.
-
- when(mMockUserManager.isUserRunning(eq(USER_0))).thenReturn(true);
-
LauncherApps.Callback c0 = mock(LauncherApps.Callback.class);
// Set listeners
@@ -2261,7 +3100,7 @@
});
runWithCaller(CALLING_PACKAGE_1, UserHandle.USER_SYSTEM, () -> {
- assertTrue(mManager.setDynamicShortcuts(Arrays.asList(
+ assertTrue(mManager.setDynamicShortcuts(list(
makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"))));
});
@@ -2270,7 +3109,7 @@
verify(c0).onShortcutsChanged(
eq(CALLING_PACKAGE_1),
shortcuts.capture(),
- eq(UserHandle.of(USER_0))
+ eq(HANDLE_USER_0)
);
assertShortcutIds(assertAllDynamic(shortcuts.getValue()),
"s1", "s2", "s3");
@@ -2278,7 +3117,7 @@
// From different package.
reset(c0);
runWithCaller(CALLING_PACKAGE_2, UserHandle.USER_SYSTEM, () -> {
- assertTrue(mManager.setDynamicShortcuts(Arrays.asList(
+ assertTrue(mManager.setDynamicShortcuts(list(
makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"))));
});
waitOnMainThread();
@@ -2286,7 +3125,7 @@
verify(c0).onShortcutsChanged(
eq(CALLING_PACKAGE_2),
shortcuts.capture(),
- eq(UserHandle.of(USER_0))
+ eq(HANDLE_USER_0)
);
assertShortcutIds(assertAllDynamic(shortcuts.getValue()),
"s1", "s2", "s3");
@@ -2294,7 +3133,7 @@
// Different user, callback shouldn't be called.
reset(c0);
runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
- assertTrue(mManager.setDynamicShortcuts(Arrays.asList(
+ assertTrue(mManager.setDynamicShortcuts(list(
makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"))));
});
waitOnMainThread();
@@ -2307,6 +3146,7 @@
// Test for addDynamicShortcut.
reset(c0);
runWithCaller(CALLING_PACKAGE_1, UserHandle.USER_SYSTEM, () -> {
+ dumpsysOnLogcat("before addDynamicShortcut");
assertTrue(mManager.addDynamicShortcut(makeShortcut("s4")));
});
@@ -2315,7 +3155,7 @@
verify(c0).onShortcutsChanged(
eq(CALLING_PACKAGE_1),
shortcuts.capture(),
- eq(UserHandle.of(USER_0))
+ eq(HANDLE_USER_0)
);
assertShortcutIds(assertAllDynamic(shortcuts.getValue()),
"s1", "s2", "s3", "s4");
@@ -2331,7 +3171,7 @@
verify(c0).onShortcutsChanged(
eq(CALLING_PACKAGE_1),
shortcuts.capture(),
- eq(UserHandle.of(USER_0))
+ eq(HANDLE_USER_0)
);
assertShortcutIds(assertAllDynamic(shortcuts.getValue()),
"s2", "s3", "s4");
@@ -2339,7 +3179,7 @@
// Test for update
reset(c0);
runWithCaller(CALLING_PACKAGE_1, UserHandle.USER_SYSTEM, () -> {
- assertTrue(mManager.updateShortcuts(Arrays.asList(
+ assertTrue(mManager.updateShortcuts(list(
makeShortcut("s1"), makeShortcut("s2"))));
});
@@ -2348,7 +3188,7 @@
verify(c0).onShortcutsChanged(
eq(CALLING_PACKAGE_1),
shortcuts.capture(),
- eq(UserHandle.of(USER_0))
+ eq(HANDLE_USER_0)
);
assertShortcutIds(assertAllDynamic(shortcuts.getValue()),
"s2", "s3", "s4");
@@ -2364,13 +3204,14 @@
verify(c0).onShortcutsChanged(
eq(CALLING_PACKAGE_1),
shortcuts.capture(),
- eq(UserHandle.of(USER_0))
+ eq(HANDLE_USER_0)
);
assertEquals(0, shortcuts.getValue().size());
// Remove CALLING_PACKAGE_2
reset(c0);
- mService.cleanUpPackageLocked(CALLING_PACKAGE_2, USER_0);
+ uninstallPackage(USER_0, CALLING_PACKAGE_2);
+ mService.cleanUpPackageLocked(CALLING_PACKAGE_2, USER_0, USER_0);
// Should get a callback with an empty list.
waitOnMainThread();
@@ -2378,15 +3219,165 @@
verify(c0).onShortcutsChanged(
eq(CALLING_PACKAGE_2),
shortcuts.capture(),
- eq(UserHandle.of(USER_0))
+ eq(HANDLE_USER_0)
);
assertEquals(0, shortcuts.getValue().size());
}
+ private void assertCallbackNotReceived(LauncherApps.Callback mock) {
+ verify(mock, times(0)).onShortcutsChanged(anyString(), anyList(),
+ any(UserHandle.class));
+ }
+
+ private void assertCallbackReceived(LauncherApps.Callback mock,
+ UserHandle user, String packageName, String... ids) {
+ ArgumentCaptor<List> shortcutsCaptor = ArgumentCaptor.forClass(List.class);
+
+ verify(mock, times(1)).onShortcutsChanged(eq(packageName), shortcutsCaptor.capture(),
+ eq(user));
+ assertShortcutIds(shortcutsCaptor.getValue(), ids);
+ }
+
+ public void testLauncherCallback_crossProfile() throws Throwable {
+ prepareCrossProfileDataSet();
+
+ final Handler h = new Handler(Looper.getMainLooper());
+
+ final LauncherApps.Callback c0_1 = mock(LauncherApps.Callback.class);
+ final LauncherApps.Callback c0_2 = mock(LauncherApps.Callback.class);
+ final LauncherApps.Callback c0_3 = mock(LauncherApps.Callback.class);
+ final LauncherApps.Callback c0_4 = mock(LauncherApps.Callback.class);
+
+ final LauncherApps.Callback cP0_1 = mock(LauncherApps.Callback.class);
+ final LauncherApps.Callback c10_1 = mock(LauncherApps.Callback.class);
+ final LauncherApps.Callback c10_2 = mock(LauncherApps.Callback.class);
+ final LauncherApps.Callback c11_1 = mock(LauncherApps.Callback.class);
+
+ final List<LauncherApps.Callback> all =
+ list(c0_1, c0_2, c0_3, c0_4, cP0_1, c10_1, c11_1);
+
+ setDefaultLauncherChecker((pkg, userId) -> {
+ switch (userId) {
+ case USER_0:
+ return LAUNCHER_2.equals(pkg);
+ case USER_P0:
+ return LAUNCHER_1.equals(pkg);
+ case USER_10:
+ return LAUNCHER_1.equals(pkg);
+ case USER_11:
+ return LAUNCHER_1.equals(pkg);
+ default:
+ return false;
+ }
+ });
+
+ runWithCaller(LAUNCHER_1, USER_0, () -> mLauncherApps.registerCallback(c0_1, h));
+ runWithCaller(LAUNCHER_2, USER_0, () -> mLauncherApps.registerCallback(c0_2, h));
+ runWithCaller(LAUNCHER_3, USER_0, () -> mLauncherApps.registerCallback(c0_3, h));
+ runWithCaller(LAUNCHER_4, USER_0, () -> mLauncherApps.registerCallback(c0_4, h));
+ runWithCaller(LAUNCHER_1, USER_P0, () -> mLauncherApps.registerCallback(cP0_1, h));
+ runWithCaller(LAUNCHER_1, USER_10, () -> mLauncherApps.registerCallback(c10_1, h));
+ runWithCaller(LAUNCHER_2, USER_10, () -> mLauncherApps.registerCallback(c10_2, h));
+ runWithCaller(LAUNCHER_1, USER_11, () -> mLauncherApps.registerCallback(c11_1, h));
+
+ // User 0.
+
+ resetAll(all);
+ runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+ mManager.deleteDynamicShortcut("x");
+ });
+ waitOnMainThread();
+
+ assertCallbackNotReceived(c0_1);
+ assertCallbackNotReceived(c0_3);
+ assertCallbackNotReceived(c0_4);
+ assertCallbackNotReceived(c10_1);
+ assertCallbackNotReceived(c10_2);
+ assertCallbackNotReceived(c11_1);
+ assertCallbackReceived(c0_2, HANDLE_USER_0, CALLING_PACKAGE_1, "s1", "s2", "s3");
+ assertCallbackReceived(cP0_1, HANDLE_USER_0, CALLING_PACKAGE_1, "s1", "s2", "s3", "s4");
+
+ // User 0, different package.
+
+ resetAll(all);
+ runWithCaller(CALLING_PACKAGE_3, USER_0, () -> {
+ mManager.deleteDynamicShortcut("x");
+ });
+ waitOnMainThread();
+
+ assertCallbackNotReceived(c0_1);
+ assertCallbackNotReceived(c0_3);
+ assertCallbackNotReceived(c0_4);
+ assertCallbackNotReceived(c10_1);
+ assertCallbackNotReceived(c10_2);
+ assertCallbackNotReceived(c11_1);
+ assertCallbackReceived(c0_2, HANDLE_USER_0, CALLING_PACKAGE_3, "s1", "s2", "s3", "s4");
+ assertCallbackReceived(cP0_1, HANDLE_USER_0, CALLING_PACKAGE_3,
+ "s1", "s2", "s3", "s4", "s5", "s6");
+
+ // Work profile, but not running, so don't send notifications.
+
+ resetAll(all);
+ runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
+ mManager.deleteDynamicShortcut("x");
+ });
+ waitOnMainThread();
+
+ assertCallbackNotReceived(c0_1);
+ assertCallbackNotReceived(c0_2);
+ assertCallbackNotReceived(c0_3);
+ assertCallbackNotReceived(c0_4);
+ assertCallbackNotReceived(cP0_1);
+ assertCallbackNotReceived(c10_1);
+ assertCallbackNotReceived(c10_2);
+ assertCallbackNotReceived(c11_1);
+
+ // Work profile, now running.
+
+ when(mMockUserManager.isUserRunning(anyInt())).thenReturn(false);
+ when(mMockUserManager.isUserRunning(eq(USER_P0))).thenReturn(true);
+
+ resetAll(all);
+ runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
+ mManager.deleteDynamicShortcut("x");
+ });
+ waitOnMainThread();
+
+ assertCallbackNotReceived(c0_1);
+ assertCallbackNotReceived(c0_3);
+ assertCallbackNotReceived(c0_4);
+ assertCallbackNotReceived(c10_1);
+ assertCallbackNotReceived(c10_2);
+ assertCallbackNotReceived(c11_1);
+ assertCallbackReceived(c0_2, HANDLE_USER_P0, CALLING_PACKAGE_1, "s1", "s2", "s3", "s5");
+ assertCallbackReceived(cP0_1, HANDLE_USER_P0, CALLING_PACKAGE_1, "s1", "s2", "s3", "s4");
+
+ // Normal secondary user.
+
+ when(mMockUserManager.isUserRunning(anyInt())).thenReturn(false);
+ when(mMockUserManager.isUserRunning(eq(USER_10))).thenReturn(true);
+
+ resetAll(all);
+ runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
+ mManager.deleteDynamicShortcut("x");
+ });
+ waitOnMainThread();
+
+ assertCallbackNotReceived(c0_1);
+ assertCallbackNotReceived(c0_2);
+ assertCallbackNotReceived(c0_3);
+ assertCallbackNotReceived(c0_4);
+ assertCallbackNotReceived(cP0_1);
+ assertCallbackNotReceived(c10_2);
+ assertCallbackNotReceived(c11_1);
+ assertCallbackReceived(c10_1, HANDLE_USER_10, CALLING_PACKAGE_1,
+ "x1", "x2", "x3", "x4", "x5");
+ }
+
// === Test for persisting ===
public void testSaveAndLoadUser_empty() {
- assertTrue(mManager.setDynamicShortcuts(Arrays.asList()));
+ assertTrue(mManager.setDynamicShortcuts(list()));
Log.i(TAG, "Saved state");
dumpsysOnLogcat();
@@ -2426,7 +3417,7 @@
makeIntent(Intent.ACTION_ASSIST, ShortcutActivity3.class),
/* weight */ 12);
- assertTrue(mManager.setDynamicShortcuts(Arrays.asList(si1, si2)));
+ assertTrue(mManager.setDynamicShortcuts(list(si1, si2)));
assertEquals(START_TIME + INTERVAL, mManager.getRateLimitResetTime());
assertEquals(2, mManager.getRemainingCallCount());
@@ -2453,7 +3444,7 @@
makeIntent(Intent.ACTION_ASSIST, ShortcutActivity3.class),
/* weight */ 12);
- assertTrue(mManager.setDynamicShortcuts(Arrays.asList(si1, si2)));
+ assertTrue(mManager.setDynamicShortcuts(list(si1, si2)));
assertEquals(START_TIME + INTERVAL, mManager.getRateLimitResetTime());
assertEquals(2, mManager.getRemainingCallCount());
@@ -2480,7 +3471,7 @@
makeIntent(Intent.ACTION_ASSIST, ShortcutActivity3.class),
/* weight */ 12);
- assertTrue(mManager.setDynamicShortcuts(Arrays.asList(si1, si2)));
+ assertTrue(mManager.setDynamicShortcuts(list(si1, si2)));
assertEquals(START_TIME + INTERVAL, mManager.getRateLimitResetTime());
assertEquals(2, mManager.getRemainingCallCount());
@@ -2549,45 +3540,45 @@
public void testCleanupPackage() {
runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
- assertTrue(mManager.setDynamicShortcuts(Arrays.asList(
+ assertTrue(mManager.setDynamicShortcuts(list(
makeShortcut("s0_1"))));
});
runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
- assertTrue(mManager.setDynamicShortcuts(Arrays.asList(
+ assertTrue(mManager.setDynamicShortcuts(list(
makeShortcut("s0_2"))));
});
runWithCaller(LAUNCHER_1, USER_0, () -> {
- mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, Arrays.asList("s0_1"),
- UserHandle.of(USER_0));
- mLauncherApps.pinShortcuts(CALLING_PACKAGE_2, Arrays.asList("s0_2"),
- UserHandle.of(USER_0));
+ mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s0_1"),
+ HANDLE_USER_0);
+ mLauncherApps.pinShortcuts(CALLING_PACKAGE_2, list("s0_2"),
+ HANDLE_USER_0);
});
runWithCaller(LAUNCHER_2, USER_0, () -> {
- mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, Arrays.asList("s0_1"),
- UserHandle.of(USER_0));
- mLauncherApps.pinShortcuts(CALLING_PACKAGE_2, Arrays.asList("s0_2"),
- UserHandle.of(USER_0));
+ mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s0_1"),
+ HANDLE_USER_0);
+ mLauncherApps.pinShortcuts(CALLING_PACKAGE_2, list("s0_2"),
+ HANDLE_USER_0);
});
runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
- assertTrue(mManager.setDynamicShortcuts(Arrays.asList(
+ assertTrue(mManager.setDynamicShortcuts(list(
makeShortcut("s10_1"))));
});
runWithCaller(CALLING_PACKAGE_2, USER_10, () -> {
- assertTrue(mManager.setDynamicShortcuts(Arrays.asList(
+ assertTrue(mManager.setDynamicShortcuts(list(
makeShortcut("s10_2"))));
});
runWithCaller(LAUNCHER_1, USER_10, () -> {
- mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, Arrays.asList("s10_1"),
- UserHandle.of(USER_10));
- mLauncherApps.pinShortcuts(CALLING_PACKAGE_2, Arrays.asList("s10_2"),
- UserHandle.of(USER_10));
+ mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s10_1"),
+ HANDLE_USER_10);
+ mLauncherApps.pinShortcuts(CALLING_PACKAGE_2, list("s10_2"),
+ HANDLE_USER_10);
});
runWithCaller(LAUNCHER_2, USER_10, () -> {
- mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, Arrays.asList("s10_1"),
- UserHandle.of(USER_10));
- mLauncherApps.pinShortcuts(CALLING_PACKAGE_2, Arrays.asList("s10_2"),
- UserHandle.of(USER_10));
+ mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s10_1"),
+ HANDLE_USER_10);
+ mLauncherApps.pinShortcuts(CALLING_PACKAGE_2, list("s10_2"),
+ HANDLE_USER_10);
});
// Remove all dynamic shortcuts; now all shortcuts are just pinned.
@@ -2615,15 +3606,19 @@
// Check the registered packages.
-
+ dumpsysOnLogcat();
assertEquals(makeSet(CALLING_PACKAGE_1, CALLING_PACKAGE_2),
- set(user0.getPackages().keySet()));
+ set(user0.getAllPackages().keySet()));
assertEquals(makeSet(CALLING_PACKAGE_1, CALLING_PACKAGE_2),
- set(user10.getPackages().keySet()));
- assertEquals(makeSet(LAUNCHER_1, LAUNCHER_2),
- set(user0.getLaunchers().keySet()));
- assertEquals(makeSet(LAUNCHER_1, LAUNCHER_2),
- set(user10.getLaunchers().keySet()));
+ set(user10.getAllPackages().keySet()));
+ assertEquals(
+ makeSet(PackageWithUser.of(USER_0, LAUNCHER_1),
+ PackageWithUser.of(USER_0, LAUNCHER_2)),
+ set(user0.getAllLaunchers().keySet()));
+ assertEquals(
+ makeSet(PackageWithUser.of(USER_10, LAUNCHER_1),
+ PackageWithUser.of(USER_10, LAUNCHER_2)),
+ set(user10.getAllLaunchers().keySet()));
assertShortcutIds(getLauncherPinnedShortcuts(LAUNCHER_1, USER_0),
"s0_1", "s0_2");
assertShortcutIds(getLauncherPinnedShortcuts(LAUNCHER_2, USER_0),
@@ -2640,17 +3635,22 @@
mService.saveDirtyInfo();
// Nonexistent package.
- mService.cleanUpPackageLocked("abc", USER_0);
+ uninstallPackage(USER_0, "abc");
+ mService.cleanUpPackageLocked("abc", USER_0, USER_0);
// No changes.
assertEquals(makeSet(CALLING_PACKAGE_1, CALLING_PACKAGE_2),
- set(user0.getPackages().keySet()));
+ set(user0.getAllPackages().keySet()));
assertEquals(makeSet(CALLING_PACKAGE_1, CALLING_PACKAGE_2),
- set(user10.getPackages().keySet()));
- assertEquals(makeSet(LAUNCHER_1, LAUNCHER_2),
- set(user0.getLaunchers().keySet()));
- assertEquals(makeSet(LAUNCHER_1, LAUNCHER_2),
- set(user10.getLaunchers().keySet()));
+ set(user10.getAllPackages().keySet()));
+ assertEquals(
+ makeSet(PackageWithUser.of(USER_0, LAUNCHER_1),
+ PackageWithUser.of(USER_0, LAUNCHER_2)),
+ set(user0.getAllLaunchers().keySet()));
+ assertEquals(
+ makeSet(PackageWithUser.of(USER_10, LAUNCHER_1),
+ PackageWithUser.of(USER_10, LAUNCHER_2)),
+ set(user10.getAllLaunchers().keySet()));
assertShortcutIds(getLauncherPinnedShortcuts(LAUNCHER_1, USER_0),
"s0_1", "s0_2");
assertShortcutIds(getLauncherPinnedShortcuts(LAUNCHER_2, USER_0),
@@ -2667,16 +3667,21 @@
mService.saveDirtyInfo();
// Remove a package.
- mService.cleanUpPackageLocked(CALLING_PACKAGE_1, USER_0);
+ uninstallPackage(USER_0, CALLING_PACKAGE_1);
+ mService.cleanUpPackageLocked(CALLING_PACKAGE_1, USER_0, USER_0);
assertEquals(makeSet(CALLING_PACKAGE_2),
- set(user0.getPackages().keySet()));
+ set(user0.getAllPackages().keySet()));
assertEquals(makeSet(CALLING_PACKAGE_1, CALLING_PACKAGE_2),
- set(user10.getPackages().keySet()));
- assertEquals(makeSet(LAUNCHER_1, LAUNCHER_2),
- set(user0.getLaunchers().keySet()));
- assertEquals(makeSet(LAUNCHER_1, LAUNCHER_2),
- set(user10.getLaunchers().keySet()));
+ set(user10.getAllPackages().keySet()));
+ assertEquals(
+ makeSet(PackageWithUser.of(USER_0, LAUNCHER_1),
+ PackageWithUser.of(USER_0, LAUNCHER_2)),
+ set(user0.getAllLaunchers().keySet()));
+ assertEquals(
+ makeSet(PackageWithUser.of(USER_10, LAUNCHER_1),
+ PackageWithUser.of(USER_10, LAUNCHER_2)),
+ set(user10.getAllLaunchers().keySet()));
assertShortcutIds(getLauncherPinnedShortcuts(LAUNCHER_1, USER_0),
"s0_2");
assertShortcutIds(getLauncherPinnedShortcuts(LAUNCHER_2, USER_0),
@@ -2693,16 +3698,20 @@
mService.saveDirtyInfo();
// Remove a launcher.
- mService.cleanUpPackageLocked(LAUNCHER_1, USER_10);
+ uninstallPackage(USER_10, LAUNCHER_1);
+ mService.cleanUpPackageLocked(LAUNCHER_1, USER_10, USER_10);
assertEquals(makeSet(CALLING_PACKAGE_2),
- set(user0.getPackages().keySet()));
+ set(user0.getAllPackages().keySet()));
assertEquals(makeSet(CALLING_PACKAGE_1, CALLING_PACKAGE_2),
- set(user10.getPackages().keySet()));
- assertEquals(makeSet(LAUNCHER_1, LAUNCHER_2),
- set(user0.getLaunchers().keySet()));
- assertEquals(makeSet(LAUNCHER_2),
- set(user10.getLaunchers().keySet()));
+ set(user10.getAllPackages().keySet()));
+ assertEquals(
+ makeSet(PackageWithUser.of(USER_0, LAUNCHER_1),
+ PackageWithUser.of(USER_0, LAUNCHER_2)),
+ set(user0.getAllLaunchers().keySet()));
+ assertEquals(
+ makeSet(PackageWithUser.of(USER_10, LAUNCHER_2)),
+ set(user10.getAllLaunchers().keySet()));
assertShortcutIds(getLauncherPinnedShortcuts(LAUNCHER_1, USER_0),
"s0_2");
assertShortcutIds(getLauncherPinnedShortcuts(LAUNCHER_2, USER_0),
@@ -2717,16 +3726,20 @@
mService.saveDirtyInfo();
// Remove a package.
- mService.cleanUpPackageLocked(CALLING_PACKAGE_2, USER_10);
+ uninstallPackage(USER_10, CALLING_PACKAGE_2);
+ mService.cleanUpPackageLocked(CALLING_PACKAGE_2, USER_10, USER_10);
assertEquals(makeSet(CALLING_PACKAGE_2),
- set(user0.getPackages().keySet()));
+ set(user0.getAllPackages().keySet()));
assertEquals(makeSet(CALLING_PACKAGE_1),
- set(user10.getPackages().keySet()));
- assertEquals(makeSet(LAUNCHER_1, LAUNCHER_2),
- set(user0.getLaunchers().keySet()));
- assertEquals(makeSet(LAUNCHER_2),
- set(user10.getLaunchers().keySet()));
+ set(user10.getAllPackages().keySet()));
+ assertEquals(
+ makeSet(PackageWithUser.of(USER_0, LAUNCHER_1),
+ PackageWithUser.of(USER_0, LAUNCHER_2)),
+ set(user0.getAllLaunchers().keySet()));
+ assertEquals(
+ makeSet(PackageWithUser.of(USER_10, LAUNCHER_2)),
+ set(user10.getAllLaunchers().keySet()));
assertShortcutIds(getLauncherPinnedShortcuts(LAUNCHER_1, USER_0),
"s0_2");
assertShortcutIds(getLauncherPinnedShortcuts(LAUNCHER_2, USER_0),
@@ -2741,16 +3754,20 @@
mService.saveDirtyInfo();
// Remove the other launcher from user 10 too.
- mService.cleanUpPackageLocked(LAUNCHER_2, USER_10);
+ uninstallPackage(USER_10, LAUNCHER_2);
+ mService.cleanUpPackageLocked(LAUNCHER_2, USER_10, USER_10);
assertEquals(makeSet(CALLING_PACKAGE_2),
- set(user0.getPackages().keySet()));
+ set(user0.getAllPackages().keySet()));
assertEquals(makeSet(CALLING_PACKAGE_1),
- set(user10.getPackages().keySet()));
- assertEquals(makeSet(LAUNCHER_1, LAUNCHER_2),
- set(user0.getLaunchers().keySet()));
- assertEquals(makeSet(),
- set(user10.getLaunchers().keySet()));
+ set(user10.getAllPackages().keySet()));
+ assertEquals(
+ makeSet(PackageWithUser.of(USER_0, LAUNCHER_1),
+ PackageWithUser.of(USER_0, LAUNCHER_2)),
+ set(user0.getAllLaunchers().keySet()));
+ assertEquals(
+ makeSet(),
+ set(user10.getAllLaunchers().keySet()));
assertShortcutIds(getLauncherPinnedShortcuts(LAUNCHER_1, USER_0),
"s0_2");
assertShortcutIds(getLauncherPinnedShortcuts(LAUNCHER_2, USER_0),
@@ -2765,16 +3782,19 @@
mService.saveDirtyInfo();
// More remove.
- mService.cleanUpPackageLocked(CALLING_PACKAGE_1, USER_10);
+ uninstallPackage(USER_10, CALLING_PACKAGE_1);
+ mService.cleanUpPackageLocked(CALLING_PACKAGE_1, USER_10, USER_10);
assertEquals(makeSet(CALLING_PACKAGE_2),
- set(user0.getPackages().keySet()));
+ set(user0.getAllPackages().keySet()));
assertEquals(makeSet(),
- set(user10.getPackages().keySet()));
- assertEquals(makeSet(LAUNCHER_1, LAUNCHER_2),
- set(user0.getLaunchers().keySet()));
+ set(user10.getAllPackages().keySet()));
+ assertEquals(
+ makeSet(PackageWithUser.of(USER_0, LAUNCHER_1),
+ PackageWithUser.of(USER_0, LAUNCHER_2)),
+ set(user0.getAllLaunchers().keySet()));
assertEquals(makeSet(),
- set(user10.getLaunchers().keySet()));
+ set(user10.getAllLaunchers().keySet()));
assertShortcutIds(getLauncherPinnedShortcuts(LAUNCHER_1, USER_0),
"s0_2");
assertShortcutIds(getLauncherPinnedShortcuts(LAUNCHER_2, USER_0),
@@ -2789,7 +3809,1567 @@
mService.saveDirtyInfo();
}
- // TODO Detailed test for hasShortcutPermissionInner().
+ public void testHandleGonePackage_crossProfile() {
+ // Create some shortcuts.
+ runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+ assertTrue(mManager.setDynamicShortcuts(list(
+ makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"))));
+ });
+ runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
+ assertTrue(mManager.setDynamicShortcuts(list(
+ makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"))));
+ });
+ runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
+ assertTrue(mManager.setDynamicShortcuts(list(
+ makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"))));
+ });
+ runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
+ assertTrue(mManager.setDynamicShortcuts(list(
+ makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"))));
+ });
- // TODO Add tests for the command line functions too.
+ assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_0));
+ assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_0));
+ assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_0));
+
+ assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_P0));
+ assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_P0));
+ assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_P0));
+
+ assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_2, "s1", USER_0));
+ assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_2, "s2", USER_0));
+ assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_2, "s3", USER_0));
+
+ assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_10));
+ assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_10));
+ assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_10));
+
+ // Pin some.
+
+ runWithCaller(LAUNCHER_1, USER_0, () -> {
+ mLauncherApps.pinShortcuts(CALLING_PACKAGE_1,
+ list("s1"), HANDLE_USER_0);
+
+ mLauncherApps.pinShortcuts(CALLING_PACKAGE_1,
+ list("s2"), UserHandle.of(USER_P0));
+
+ mLauncherApps.pinShortcuts(CALLING_PACKAGE_2,
+ list("s3"), HANDLE_USER_0);
+ });
+
+ runWithCaller(LAUNCHER_1, USER_P0, () -> {
+ mLauncherApps.pinShortcuts(CALLING_PACKAGE_1,
+ list("s2"), HANDLE_USER_0);
+
+ mLauncherApps.pinShortcuts(CALLING_PACKAGE_1,
+ list("s3"), UserHandle.of(USER_P0));
+
+ mLauncherApps.pinShortcuts(CALLING_PACKAGE_2,
+ list("s1"), HANDLE_USER_0);
+ });
+
+ runWithCaller(LAUNCHER_1, USER_10, () -> {
+ mLauncherApps.pinShortcuts(CALLING_PACKAGE_1,
+ list("s3"), HANDLE_USER_10);
+ });
+
+ // Check the state.
+
+ assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_0));
+ assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_0));
+ assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_0));
+
+ assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_P0));
+ assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_P0));
+ assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_P0));
+
+ assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_2, "s1", USER_0));
+ assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_2, "s2", USER_0));
+ assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_2, "s3", USER_0));
+
+ assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_10));
+ assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_10));
+ assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_10));
+
+ // Make sure all the information is persisted.
+ mService.saveDirtyInfo();
+ initService();
+ mService.handleUnlockUser(USER_0);
+ mService.handleUnlockUser(USER_P0);
+ mService.handleUnlockUser(USER_10);
+
+ assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_0));
+ assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_0));
+ assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_0));
+
+ assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_P0));
+ assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_P0));
+ assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_P0));
+
+ assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_2, "s1", USER_0));
+ assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_2, "s2", USER_0));
+ assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_2, "s3", USER_0));
+
+ assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_10));
+ assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_10));
+ assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_10));
+
+ // Start uninstalling.
+ uninstallPackage(USER_10, LAUNCHER_1);
+ mService.cleanupGonePackages(USER_10);
+
+ assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_0));
+ assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_0));
+ assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_0));
+
+ assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_P0));
+ assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_P0));
+ assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_P0));
+
+ assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_2, "s1", USER_0));
+ assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_2, "s2", USER_0));
+ assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_2, "s3", USER_0));
+
+ assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_10));
+ assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_10));
+ assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_10));
+
+ // Uninstall.
+ uninstallPackage(USER_10, CALLING_PACKAGE_1);
+ mService.cleanupGonePackages(USER_10);
+
+ assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_0));
+ assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_0));
+ assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_0));
+
+ assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_P0));
+ assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_P0));
+ assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_P0));
+
+ assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_2, "s1", USER_0));
+ assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_2, "s2", USER_0));
+ assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_2, "s3", USER_0));
+
+ assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_10));
+ assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_10));
+ assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_10));
+
+ uninstallPackage(USER_P0, LAUNCHER_1);
+ mService.cleanupGonePackages(USER_0);
+
+ assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_0));
+ assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_0));
+ assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_0));
+
+ assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_P0));
+ assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_P0));
+ assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_P0));
+
+ assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_2, "s1", USER_0));
+ assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_2, "s2", USER_0));
+ assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_2, "s3", USER_0));
+
+ assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_10));
+ assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_10));
+ assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_10));
+
+ mService.cleanupGonePackages(USER_P0);
+
+ assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_0));
+ assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_0));
+ assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_0));
+
+ assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_P0));
+ assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_P0));
+ assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_P0));
+
+ assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_2, "s1", USER_0));
+ assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_2, "s2", USER_0));
+ assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_2, "s3", USER_0));
+
+ assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_10));
+ assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_10));
+ assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_10));
+
+ uninstallPackage(USER_P0, CALLING_PACKAGE_1);
+
+ mService.saveDirtyInfo();
+ initService();
+ mService.handleUnlockUser(USER_0);
+ mService.handleUnlockUser(USER_P0);
+ mService.handleUnlockUser(USER_10);
+
+ assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_0));
+ assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_0));
+ assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_0));
+
+ assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_P0));
+ assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_P0));
+ assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_P0));
+
+ assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_2, "s1", USER_0));
+ assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_2, "s2", USER_0));
+ assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_2, "s3", USER_0));
+
+ assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_10));
+ assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_10));
+ assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_10));
+
+ // Uninstall
+ uninstallPackage(USER_0, LAUNCHER_1);
+
+ mService.saveDirtyInfo();
+ initService();
+ mService.handleUnlockUser(USER_0);
+ mService.handleUnlockUser(USER_P0);
+ mService.handleUnlockUser(USER_10);
+
+ assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_0));
+ assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_0));
+ assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_0));
+
+ assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_P0));
+ assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_P0));
+ assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_P0));
+
+ assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_2, "s1", USER_0));
+ assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_2, "s2", USER_0));
+ assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_2, "s3", USER_0));
+
+ assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_10));
+ assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_10));
+ assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_10));
+
+ uninstallPackage(USER_0, CALLING_PACKAGE_2);
+
+ mService.saveDirtyInfo();
+ initService();
+ mService.handleUnlockUser(USER_0);
+ mService.handleUnlockUser(USER_P0);
+ mService.handleUnlockUser(USER_10);
+
+ assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_0));
+ assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_0));
+ assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_0));
+
+ assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_P0));
+ assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_P0));
+ assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_P0));
+
+ assertNull(getPackageShortcut(CALLING_PACKAGE_2, "s1", USER_0));
+ assertNull(getPackageShortcut(CALLING_PACKAGE_2, "s2", USER_0));
+ assertNull(getPackageShortcut(CALLING_PACKAGE_2, "s3", USER_0));
+
+ assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_10));
+ assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_10));
+ assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_10));
+ }
+
+ private void checkCanRestoreTo(boolean expected, ShortcutPackageInfo spi,
+ int version, String... signatures) {
+ assertEquals(expected, spi.canRestoreTo(mService, genPackage(
+ "dummy", /* uid */ 0, version, signatures)));
+ }
+
+ public void testCanRestoreTo() {
+ addPackage(CALLING_PACKAGE_1, CALLING_UID_1, 10, "sig1");
+ addPackage(CALLING_PACKAGE_2, CALLING_UID_1, 10, "sig1", "sig2");
+
+ final ShortcutPackageInfo spi1 = ShortcutPackageInfo.generateForInstalledPackage(
+ mService, CALLING_PACKAGE_1, USER_0);
+ final ShortcutPackageInfo spi2 = ShortcutPackageInfo.generateForInstalledPackage(
+ mService, CALLING_PACKAGE_2, USER_0);
+
+ checkCanRestoreTo(true, spi1, 10, "sig1");
+ checkCanRestoreTo(true, spi1, 10, "x", "sig1");
+ checkCanRestoreTo(true, spi1, 10, "sig1", "y");
+ checkCanRestoreTo(true, spi1, 10, "x", "sig1", "y");
+ checkCanRestoreTo(true, spi1, 11, "sig1");
+
+ checkCanRestoreTo(false, spi1, 10 /* empty */);
+ checkCanRestoreTo(false, spi1, 10, "x");
+ checkCanRestoreTo(false, spi1, 10, "x", "y");
+ checkCanRestoreTo(false, spi1, 10, "x");
+ checkCanRestoreTo(false, spi1, 9, "sig1");
+
+ checkCanRestoreTo(true, spi2, 10, "sig1", "sig2");
+ checkCanRestoreTo(true, spi2, 10, "sig2", "sig1");
+ checkCanRestoreTo(true, spi2, 10, "x", "sig1", "sig2");
+ checkCanRestoreTo(true, spi2, 10, "x", "sig2", "sig1");
+ checkCanRestoreTo(true, spi2, 10, "sig1", "sig2", "y");
+ checkCanRestoreTo(true, spi2, 10, "sig2", "sig1", "y");
+ checkCanRestoreTo(true, spi2, 10, "x", "sig1", "sig2", "y");
+ checkCanRestoreTo(true, spi2, 10, "x", "sig2", "sig1", "y");
+ checkCanRestoreTo(true, spi2, 11, "x", "sig2", "sig1", "y");
+
+ checkCanRestoreTo(false, spi2, 10, "sig1", "sig2x");
+ checkCanRestoreTo(false, spi2, 10, "sig2", "sig1x");
+ checkCanRestoreTo(false, spi2, 10, "x", "sig1x", "sig2");
+ checkCanRestoreTo(false, spi2, 10, "x", "sig2x", "sig1");
+ checkCanRestoreTo(false, spi2, 10, "sig1", "sig2x", "y");
+ checkCanRestoreTo(false, spi2, 10, "sig2", "sig1x", "y");
+ checkCanRestoreTo(false, spi2, 10, "x", "sig1x", "sig2", "y");
+ checkCanRestoreTo(false, spi2, 10, "x", "sig2x", "sig1", "y");
+ checkCanRestoreTo(false, spi2, 11, "x", "sig2x", "sig1", "y");
+ }
+
+ public void testHandlePackageDelete() {
+ setCaller(CALLING_PACKAGE_1, USER_0);
+ assertTrue(mManager.addDynamicShortcut(makeShortcut("s1")));
+
+ setCaller(CALLING_PACKAGE_2, USER_0);
+ assertTrue(mManager.addDynamicShortcut(makeShortcut("s1")));
+
+ setCaller(CALLING_PACKAGE_3, USER_0);
+ assertTrue(mManager.addDynamicShortcut(makeShortcut("s1")));
+
+ setCaller(CALLING_PACKAGE_1, USER_10);
+ assertTrue(mManager.addDynamicShortcut(makeShortcut("s1")));
+
+ setCaller(CALLING_PACKAGE_2, USER_10);
+ assertTrue(mManager.addDynamicShortcut(makeShortcut("s1")));
+
+ setCaller(CALLING_PACKAGE_3, USER_10);
+ assertTrue(mManager.addDynamicShortcut(makeShortcut("s1")));
+
+ assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "s1", USER_0));
+ assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_2, "s1", USER_0));
+ assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_3, "s1", USER_0));
+ assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "s1", USER_10));
+ assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_2, "s1", USER_10));
+ assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_3, "s1", USER_10));
+
+ uninstallPackage(USER_0, CALLING_PACKAGE_1);
+ mService.mPackageMonitor.onReceive(getTestContext(),
+ genPackageDeleteIntent(CALLING_PACKAGE_1, USER_0));
+
+ assertNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "s1", USER_0));
+ assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_2, "s1", USER_0));
+ assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_3, "s1", USER_0));
+ assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "s1", USER_10));
+ assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_2, "s1", USER_10));
+ assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_3, "s1", USER_10));
+
+ uninstallPackage(USER_10, CALLING_PACKAGE_2);
+ mService.mPackageMonitor.onReceive(getTestContext(),
+ genPackageDeleteIntent(CALLING_PACKAGE_2, USER_10));
+
+ assertNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "s1", USER_0));
+ assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_2, "s1", USER_0));
+ assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_3, "s1", USER_0));
+ assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "s1", USER_10));
+ assertNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_2, "s1", USER_10));
+ assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_3, "s1", USER_10));
+
+ mInjectedPackages.remove(CALLING_PACKAGE_1);
+ mInjectedPackages.remove(CALLING_PACKAGE_3);
+
+ mService.handleUnlockUser(USER_0);
+
+ assertNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "s1", USER_0));
+ assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_2, "s1", USER_0));
+ assertNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_3, "s1", USER_0));
+ assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "s1", USER_10));
+ assertNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_2, "s1", USER_10));
+ assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_3, "s1", USER_10));
+
+ mService.handleUnlockUser(USER_10);
+
+ assertNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "s1", USER_0));
+ assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_2, "s1", USER_0));
+ assertNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_3, "s1", USER_0));
+ assertNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "s1", USER_10));
+ assertNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_2, "s1", USER_10));
+ assertNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_3, "s1", USER_10));
+ }
+
+ private void backupAndRestore() {
+ int prevUid = mInjectedCallingUid;
+
+ mInjectedCallingUid = Process.SYSTEM_UID; // Only system can call it.
+
+ dumpsysOnLogcat("Before backup");
+
+ final byte[] payload = mService.getBackupPayload(USER_0);
+ if (ENABLE_DUMP) {
+ final String xml = new String(payload);
+ Log.i(TAG, "Backup payload:");
+ for (String line : xml.split("\n")) {
+ Log.i(TAG, line);
+ }
+ }
+
+ // Before doing anything else, uninstall all packages.
+ for (int userId : list(USER_0, USER_P0)) {
+ for (String pkg : list(CALLING_PACKAGE_1, CALLING_PACKAGE_2, CALLING_PACKAGE_3,
+ LAUNCHER_1, LAUNCHER_2, LAUNCHER_3)) {
+ uninstallPackage(userId, pkg);
+ }
+ }
+
+ shutdownServices();
+
+ deleteAllSavedFiles();
+
+ initService();
+ mService.applyRestore(payload, USER_0);
+
+ // handleUnlockUser will perform the gone package check, but it shouldn't remove
+ // shadow information.
+ mService.handleUnlockUser(USER_0);
+
+ dumpsysOnLogcat("After restore");
+
+ mInjectedCallingUid = prevUid;
+ }
+
+ private void prepareCrossProfileDataSet() {
+ runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+ assertTrue(mManager.setDynamicShortcuts(list(
+ makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"),
+ makeShortcut("s4"), makeShortcut("s5"), makeShortcut("s6"))));
+ });
+ runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
+ assertTrue(mManager.setDynamicShortcuts(list(
+ makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"),
+ makeShortcut("s4"), makeShortcut("s5"), makeShortcut("s6"))));
+ });
+ runWithCaller(CALLING_PACKAGE_3, USER_0, () -> {
+ assertTrue(mManager.setDynamicShortcuts(list(
+ makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"),
+ makeShortcut("s4"), makeShortcut("s5"), makeShortcut("s6"))));
+ });
+ runWithCaller(CALLING_PACKAGE_4, USER_0, () -> {
+ assertTrue(mManager.setDynamicShortcuts(list()));
+ });
+ runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
+ assertTrue(mManager.setDynamicShortcuts(list(
+ makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"),
+ makeShortcut("s4"), makeShortcut("s5"), makeShortcut("s6"))));
+ });
+ runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
+ assertTrue(mManager.setDynamicShortcuts(list(
+ makeShortcut("x1"), makeShortcut("x2"), makeShortcut("x3"),
+ makeShortcut("x4"), makeShortcut("x5"), makeShortcut("x6"))));
+ });
+
+ runWithCaller(LAUNCHER_1, USER_0, () -> {
+ mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s1"), HANDLE_USER_0);
+ mLauncherApps.pinShortcuts(CALLING_PACKAGE_2, list("s1", "s2"), HANDLE_USER_0);
+ mLauncherApps.pinShortcuts(CALLING_PACKAGE_3, list("s1", "s2", "s3"), HANDLE_USER_0);
+
+ mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s1", "s4"), HANDLE_USER_P0);
+ });
+ runWithCaller(LAUNCHER_2, USER_0, () -> {
+ mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s2"), HANDLE_USER_0);
+ mLauncherApps.pinShortcuts(CALLING_PACKAGE_2, list("s2", "s3"), HANDLE_USER_0);
+ mLauncherApps.pinShortcuts(CALLING_PACKAGE_3, list("s2", "s3", "s4"), HANDLE_USER_0);
+
+ mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s2", "s5"), HANDLE_USER_P0);
+ });
+ runWithCaller(LAUNCHER_3, USER_0, () -> {
+ mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s3"), HANDLE_USER_0);
+ mLauncherApps.pinShortcuts(CALLING_PACKAGE_2, list("s3", "s4"), HANDLE_USER_0);
+ mLauncherApps.pinShortcuts(CALLING_PACKAGE_3, list("s3", "s4", "s5"), HANDLE_USER_0);
+
+ mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s3", "s6"), HANDLE_USER_P0);
+ });
+ runWithCaller(LAUNCHER_4, USER_0, () -> {
+ mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list(), HANDLE_USER_0);
+ mLauncherApps.pinShortcuts(CALLING_PACKAGE_2, list(), HANDLE_USER_0);
+ mLauncherApps.pinShortcuts(CALLING_PACKAGE_3, list(), HANDLE_USER_0);
+ mLauncherApps.pinShortcuts(CALLING_PACKAGE_4, list(), HANDLE_USER_0);
+ });
+
+ // Launcher on a managed profile is referring ot user 0!
+ runWithCaller(LAUNCHER_1, USER_P0, () -> {
+ mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s3", "s4"), HANDLE_USER_0);
+ mLauncherApps.pinShortcuts(CALLING_PACKAGE_2, list("s3", "s4", "s5"), HANDLE_USER_0);
+ mLauncherApps.pinShortcuts(CALLING_PACKAGE_3, list("s3", "s4", "s5", "s6"),
+ HANDLE_USER_0);
+
+ mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s4", "s1"), HANDLE_USER_P0);
+ });
+ runWithCaller(LAUNCHER_1, USER_10, () -> {
+ mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("x4", "x5"), HANDLE_USER_10);
+ mLauncherApps.pinShortcuts(CALLING_PACKAGE_2, list("x4", "x5", "x6"), HANDLE_USER_10);
+ mLauncherApps.pinShortcuts(CALLING_PACKAGE_3, list("x4", "x5", "x6", "x1"),
+ HANDLE_USER_10);
+ });
+
+ // Then remove some dynamic shortcuts.
+ runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+ assertTrue(mManager.setDynamicShortcuts(list(
+ makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"))));
+ });
+ runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
+ assertTrue(mManager.setDynamicShortcuts(list(
+ makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"))));
+ });
+ runWithCaller(CALLING_PACKAGE_3, USER_0, () -> {
+ assertTrue(mManager.setDynamicShortcuts(list(
+ makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"))));
+ });
+ runWithCaller(CALLING_PACKAGE_4, USER_0, () -> {
+ assertTrue(mManager.setDynamicShortcuts(list()));
+ });
+ runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
+ assertTrue(mManager.setDynamicShortcuts(list(
+ makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"))));
+ });
+ runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
+ assertTrue(mManager.setDynamicShortcuts(list(
+ makeShortcut("x1"), makeShortcut("x2"), makeShortcut("x3"))));
+ });
+ }
+
+ private void prepareForBackupTest() {
+
+ prepareCrossProfileDataSet();
+
+ backupAndRestore();
+ }
+
+ private void assertExistsAndShadow(ShortcutPackageItem spi) {
+ assertNotNull(spi);
+ assertTrue(spi.getPackageInfo().isShadow());
+ }
+
+ /**
+ * Make sure the backup data doesn't have the following information:
+ * - Launchers on other users.
+ * - Non-backup app information.
+ *
+ * But restores all other infomation.
+ *
+ * It also omits the following pieces of information, but that's tested in
+ * {@link #testShortcutInfoSaveAndLoad_forBackup}.
+ * - Unpinned dynamic shortcuts
+ * - Bitmaps
+ */
+ public void testBackupAndRestore() {
+ prepareForBackupTest();
+
+ checkBackupAndRestore_success();
+ }
+
+ public void testBackupAndRestore_backupRestoreTwice() {
+ prepareForBackupTest();
+
+ // Note doing a backup & restore again here shouldn't affect the result.
+ dumpsysOnLogcat("Before second backup");
+
+ backupAndRestore();
+
+ dumpsysOnLogcat("After second backup");
+
+ checkBackupAndRestore_success();
+ }
+
+ public void testBackupAndRestore_backupRestoreMultiple() {
+ prepareForBackupTest();
+
+ // Note doing a backup & restore again here shouldn't affect the result.
+ backupAndRestore();
+
+ // This also shouldn't affect the result.
+ runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+ assertTrue(mManager.setDynamicShortcuts(list(
+ makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"),
+ makeShortcut("s4"), makeShortcut("s5"), makeShortcut("s6"))));
+ });
+
+ backupAndRestore();
+
+ checkBackupAndRestore_success();
+ }
+
+ public void testBackupAndRestore_restoreToNewVersion() {
+ prepareForBackupTest();
+
+ // Note doing a backup & restore again here shouldn't affect the result.
+ backupAndRestore();
+
+ addPackage(CALLING_PACKAGE_1, CALLING_UID_1, 2);
+ addPackage(LAUNCHER_1, LAUNCHER_UID_1, 5);
+
+ checkBackupAndRestore_success();
+ }
+
+ public void testBackupAndRestore_restoreToSuperSetSignatures() {
+ prepareForBackupTest();
+
+ // Note doing a backup & restore again here shouldn't affect the result.
+ backupAndRestore();
+
+ // Change package signatures.
+ addPackage(CALLING_PACKAGE_1, CALLING_UID_1, 1, "sigx", CALLING_PACKAGE_1);
+ addPackage(LAUNCHER_1, LAUNCHER_UID_1, 4, LAUNCHER_1, "sigy");
+
+ checkBackupAndRestore_success();
+ }
+
+ private void checkBackupAndRestore_success() {
+ // Make sure non-system user is not restored.
+ final ShortcutUser userP0 = mService.getUserShortcutsLocked(USER_P0);
+ assertEquals(0, userP0.getAllPackages().size());
+ assertEquals(0, userP0.getAllLaunchers().size());
+
+ // Make sure only "allowBackup" apps are restored, and are shadow.
+ final ShortcutUser user0 = mService.getUserShortcutsLocked(USER_0);
+ assertExistsAndShadow(user0.getAllPackages().get(CALLING_PACKAGE_1));
+ assertExistsAndShadow(user0.getAllPackages().get(CALLING_PACKAGE_2));
+ assertExistsAndShadow(user0.getAllLaunchers().get(PackageWithUser.of(USER_0, LAUNCHER_1)));
+ assertExistsAndShadow(user0.getAllLaunchers().get(PackageWithUser.of(USER_0, LAUNCHER_2)));
+
+ assertNull(user0.getAllPackages().get(CALLING_PACKAGE_3));
+ assertNull(user0.getAllLaunchers().get(PackageWithUser.of(USER_0, LAUNCHER_3)));
+ assertNull(user0.getAllLaunchers().get(PackageWithUser.of(USER_P0, LAUNCHER_1)));
+
+ installPackage(USER_0, CALLING_PACKAGE_1);
+ runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+ assertEquals(0, mManager.getDynamicShortcuts().size());
+ assertShortcutIds(assertAllPinned(
+ mManager.getPinnedShortcuts()),
+ "s1", "s2");
+ });
+
+ installPackage(USER_0, LAUNCHER_1);
+ runWithCaller(LAUNCHER_1, USER_0, () -> {
+ assertShortcutIds(assertAllPinned(
+ mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0)),
+ "s1");
+ assertShortcutIds(assertAllPinned(
+ mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0))
+ /* empty, not restored */ );
+ assertShortcutIds(assertAllPinned(
+ mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0))
+ /* empty, not restored */ );
+
+ assertEquals(0, mLauncherApps.getShortcuts(QUERY_ALL, HANDLE_USER_P0).size());
+ });
+
+ installPackage(USER_0, CALLING_PACKAGE_2);
+ runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
+ assertEquals(0, mManager.getDynamicShortcuts().size());
+ assertShortcutIds(assertAllPinned(
+ mManager.getPinnedShortcuts()),
+ "s1", "s2", "s3");
+ });
+
+ runWithCaller(LAUNCHER_1, USER_0, () -> {
+ assertShortcutIds(assertAllPinned(
+ mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0)),
+ "s1");
+ assertShortcutIds(assertAllPinned(
+ mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0)),
+ "s1", "s2");
+ assertShortcutIds(assertAllPinned(
+ mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0))
+ /* empty, not restored */ );
+
+ assertEquals(0, mLauncherApps.getShortcuts(QUERY_ALL, HANDLE_USER_P0).size());
+ });
+
+ // 3 shouldn't be backed up, so no pinned shortcuts.
+ installPackage(USER_0, CALLING_PACKAGE_3);
+ runWithCaller(CALLING_PACKAGE_3, USER_0, () -> {
+ assertEquals(0, mManager.getDynamicShortcuts().size());
+ assertEquals(0, mManager.getPinnedShortcuts().size());
+ });
+
+ // Launcher on a different profile shouldn't be restored.
+ runWithCaller(LAUNCHER_1, USER_P0, () -> {
+ assertEquals(0,
+ mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0)
+ .size());
+ assertEquals(0,
+ mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0)
+ .size());
+ assertShortcutIds(assertAllPinned(
+ mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0))
+ /* wasn't restored, so still empty */ );
+ });
+
+ // Package on a different profile, no restore.
+ installPackage(USER_P0, CALLING_PACKAGE_1);
+ runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
+ assertEquals(0, mManager.getDynamicShortcuts().size());
+ assertEquals(0, mManager.getPinnedShortcuts().size());
+ });
+
+ // Restore launcher 2 on user 0.
+ installPackage(USER_0, LAUNCHER_2);
+ runWithCaller(LAUNCHER_2, USER_0, () -> {
+ assertShortcutIds(assertAllPinned(
+ mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0)),
+ "s2");
+ assertShortcutIds(assertAllPinned(
+ mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0)),
+ "s2", "s3");
+ assertShortcutIds(assertAllPinned(
+ mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0))
+ /* wasn't restored, so still empty */ );
+
+ assertEquals(0, mLauncherApps.getShortcuts(QUERY_ALL, HANDLE_USER_P0).size());
+ });
+
+
+ // Restoration of launcher2 shouldn't affect other packages; so do the same checks and
+ // make sure they still have the same result.
+ installPackage(USER_0, CALLING_PACKAGE_1);
+ runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+ assertEquals(0, mManager.getDynamicShortcuts().size());
+ assertShortcutIds(assertAllPinned(
+ mManager.getPinnedShortcuts()),
+ "s1", "s2");
+ });
+
+ installPackage(USER_0, LAUNCHER_1);
+ runWithCaller(LAUNCHER_1, USER_0, () -> {
+ assertShortcutIds(assertAllPinned(
+ mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0)),
+ "s1");
+ assertShortcutIds(assertAllPinned(
+ mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0)),
+ "s1", "s2");
+ assertShortcutIds(assertAllPinned(
+ mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0))
+ /* wasn't restored, so still empty */ );
+
+ assertEquals(0, mLauncherApps.getShortcuts(QUERY_ALL, HANDLE_USER_P0).size());
+ });
+
+ installPackage(USER_0, CALLING_PACKAGE_2);
+ runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
+ assertEquals(0, mManager.getDynamicShortcuts().size());
+ assertShortcutIds(assertAllPinned(
+ mManager.getPinnedShortcuts()),
+ "s1", "s2", "s3");
+ });
+ }
+
+ public void testBackupAndRestore_publisherLowerVersion() {
+ prepareForBackupTest();
+
+ // Note doing a backup & restore again here shouldn't affect the result.
+ backupAndRestore();
+
+ addPackage(CALLING_PACKAGE_1, CALLING_UID_1, 0); // Lower version
+
+ checkBackupAndRestore_publisherNotRestored();
+ }
+
+ public void testBackupAndRestore_publisherWrongSignature() {
+ prepareForBackupTest();
+
+ // Note doing a backup & restore again here shouldn't affect the result.
+ backupAndRestore();
+
+ addPackage(CALLING_PACKAGE_1, CALLING_UID_1, 10, "sigx"); // different signature
+
+ checkBackupAndRestore_publisherNotRestored();
+ }
+
+ public void testBackupAndRestore_publisherNoLongerBackupTarget() {
+ prepareForBackupTest();
+
+ // Note doing a backup & restore again here shouldn't affect the result.
+ backupAndRestore();
+
+ updatePackageInfo(CALLING_PACKAGE_1,
+ pi -> pi.applicationInfo.flags &= ~ApplicationInfo.FLAG_ALLOW_BACKUP);
+
+ checkBackupAndRestore_publisherNotRestored();
+ }
+
+ private void checkBackupAndRestore_publisherNotRestored() {
+ installPackage(USER_0, CALLING_PACKAGE_1);
+ runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+ assertEquals(0, mManager.getDynamicShortcuts().size());
+ assertEquals(0, mManager.getPinnedShortcuts().size());
+ });
+
+ installPackage(USER_0, CALLING_PACKAGE_2);
+ runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
+ assertEquals(0, mManager.getDynamicShortcuts().size());
+ assertShortcutIds(assertAllPinned(
+ mManager.getPinnedShortcuts()),
+ "s1", "s2", "s3");
+ });
+
+ installPackage(USER_0, LAUNCHER_1);
+ runWithCaller(LAUNCHER_1, USER_0, () -> {
+ assertShortcutIds(assertAllPinned(
+ mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0))
+ /* empty */);
+ assertShortcutIds(assertAllPinned(
+ mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0)),
+ "s1", "s2");
+ assertShortcutIds(assertAllPinned(
+ mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0))
+ /* empty */);
+ });
+ installPackage(USER_0, LAUNCHER_2);
+ runWithCaller(LAUNCHER_2, USER_0, () -> {
+ assertShortcutIds(assertAllPinned(
+ mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0))
+ /* empty */);
+ assertShortcutIds(assertAllPinned(
+ mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0)),
+ "s2", "s3");
+ assertShortcutIds(assertAllPinned(
+ mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0))
+ /* empty */);
+ });
+
+ installPackage(USER_0, CALLING_PACKAGE_3);
+ runWithCaller(CALLING_PACKAGE_3, USER_0, () -> {
+ assertEquals(0, mManager.getDynamicShortcuts().size());
+ assertEquals(0, mManager.getPinnedShortcuts().size());
+ });
+
+ runWithCaller(LAUNCHER_1, USER_0, () -> {
+ assertShortcutIds(assertAllPinned(
+ mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0))
+ /* empty */);
+ assertShortcutIds(assertAllPinned(
+ mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0)),
+ "s1", "s2");
+ assertShortcutIds(assertAllPinned(
+ mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0))
+ /* empty */);
+ });
+ runWithCaller(LAUNCHER_2, USER_0, () -> {
+ assertShortcutIds(assertAllPinned(
+ mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0))
+ /* empty */);
+ assertShortcutIds(assertAllPinned(
+ mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0)),
+ "s2", "s3");
+ assertShortcutIds(assertAllPinned(
+ mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0))
+ /* empty */);
+ });
+ }
+
+ public void testBackupAndRestore_launcherLowerVersion() {
+ prepareForBackupTest();
+
+ // Note doing a backup & restore again here shouldn't affect the result.
+ backupAndRestore();
+
+ addPackage(LAUNCHER_1, LAUNCHER_UID_1, 0); // Lower version
+
+ checkBackupAndRestore_launcherNotRestored();
+ }
+
+ public void testBackupAndRestore_launcherWrongSignature() {
+ prepareForBackupTest();
+
+ // Note doing a backup & restore again here shouldn't affect the result.
+ backupAndRestore();
+
+ addPackage(LAUNCHER_1, LAUNCHER_UID_1, 10, "sigx"); // different signature
+
+ checkBackupAndRestore_launcherNotRestored();
+ }
+
+ public void testBackupAndRestore_launcherNoLongerBackupTarget() {
+ prepareForBackupTest();
+
+ // Note doing a backup & restore again here shouldn't affect the result.
+ backupAndRestore();
+
+ updatePackageInfo(LAUNCHER_1,
+ pi -> pi.applicationInfo.flags &= ~ApplicationInfo.FLAG_ALLOW_BACKUP);
+
+ checkBackupAndRestore_launcherNotRestored();
+ }
+
+ private void checkBackupAndRestore_launcherNotRestored() {
+ installPackage(USER_0, CALLING_PACKAGE_1);
+ runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+ assertEquals(0, mManager.getDynamicShortcuts().size());
+
+ // s1 was pinned by launcher 1, which is not restored, yet, so we still see "s1" here.
+ assertShortcutIds(assertAllPinned(
+ mManager.getPinnedShortcuts()),
+ "s1", "s2");
+ });
+
+ installPackage(USER_0, CALLING_PACKAGE_2);
+ runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
+ assertEquals(0, mManager.getDynamicShortcuts().size());
+ assertShortcutIds(assertAllPinned(
+ mManager.getPinnedShortcuts()),
+ "s1", "s2", "s3");
+ });
+
+ // Now we try to restore launcher 1. Then we realize it's not restorable, so L1 has no pinned
+ // shortcuts.
+ installPackage(USER_0, LAUNCHER_1);
+ runWithCaller(LAUNCHER_1, USER_0, () -> {
+ assertShortcutIds(assertAllPinned(
+ mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0))
+ /* empty */);
+ assertShortcutIds(assertAllPinned(
+ mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0))
+ /* empty */);
+ assertShortcutIds(assertAllPinned(
+ mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0))
+ /* empty */);
+ });
+
+ runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+ assertEquals(0, mManager.getDynamicShortcuts().size());
+
+ // Now CALLING_PACKAGE_1 realizes "s1" is no longer pinned.
+ assertShortcutIds(assertAllPinned(
+ mManager.getPinnedShortcuts()),
+ "s2");
+ });
+
+ installPackage(USER_0, LAUNCHER_2);
+ runWithCaller(LAUNCHER_2, USER_0, () -> {
+ assertShortcutIds(assertAllPinned(
+ mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0)),
+ "s2");
+ assertShortcutIds(assertAllPinned(
+ mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0)),
+ "s2", "s3");
+ assertShortcutIds(assertAllPinned(
+ mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0))
+ /* empty */);
+ });
+
+ installPackage(USER_0, CALLING_PACKAGE_3);
+ runWithCaller(CALLING_PACKAGE_3, USER_0, () -> {
+ assertEquals(0, mManager.getDynamicShortcuts().size());
+ assertEquals(0, mManager.getPinnedShortcuts().size());
+ });
+
+ runWithCaller(LAUNCHER_1, USER_0, () -> {
+ assertShortcutIds(assertAllPinned(
+ mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0))
+ /* empty */);
+ assertShortcutIds(assertAllPinned(
+ mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0))
+ /* empty */);
+ assertShortcutIds(assertAllPinned(
+ mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0))
+ /* empty */);
+ });
+ runWithCaller(LAUNCHER_2, USER_0, () -> {
+ assertShortcutIds(assertAllPinned(
+ mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0)),
+ "s2");
+ assertShortcutIds(assertAllPinned(
+ mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0)),
+ "s2", "s3");
+ assertShortcutIds(assertAllPinned(
+ mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0))
+ /* empty */);
+ });
+ }
+
+ public void testBackupAndRestore_launcherAndPackageNoLongerBackupTarget() {
+ prepareForBackupTest();
+
+ // Note doing a backup & restore again here shouldn't affect the result.
+ backupAndRestore();
+
+ updatePackageInfo(CALLING_PACKAGE_1,
+ pi -> pi.applicationInfo.flags &= ~ApplicationInfo.FLAG_ALLOW_BACKUP);
+
+ updatePackageInfo(LAUNCHER_1,
+ pi -> pi.applicationInfo.flags &= ~ApplicationInfo.FLAG_ALLOW_BACKUP);
+
+ checkBackupAndRestore_publisherAndLauncherNotRestored();
+ }
+
+ private void checkBackupAndRestore_publisherAndLauncherNotRestored() {
+ installPackage(USER_0, CALLING_PACKAGE_1);
+ runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+ assertEquals(0, mManager.getDynamicShortcuts().size());
+ assertEquals(0, mManager.getPinnedShortcuts().size());
+ });
+
+ installPackage(USER_0, CALLING_PACKAGE_2);
+ runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
+ assertEquals(0, mManager.getDynamicShortcuts().size());
+ assertShortcutIds(assertAllPinned(
+ mManager.getPinnedShortcuts()),
+ "s1", "s2", "s3");
+ });
+
+ installPackage(USER_0, LAUNCHER_1);
+ runWithCaller(LAUNCHER_1, USER_0, () -> {
+ assertShortcutIds(assertAllPinned(
+ mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0))
+ /* empty */);
+ assertShortcutIds(assertAllPinned(
+ mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0))
+ /* empty */);
+ assertShortcutIds(assertAllPinned(
+ mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0))
+ /* empty */);
+ });
+ installPackage(USER_0, LAUNCHER_2);
+ runWithCaller(LAUNCHER_2, USER_0, () -> {
+ assertShortcutIds(assertAllPinned(
+ mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0))
+ /* empty */);
+ assertShortcutIds(assertAllPinned(
+ mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0)),
+ "s2", "s3");
+ assertShortcutIds(assertAllPinned(
+ mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0))
+ /* empty */);
+ });
+
+ // Because launcher 1 wasn't restored, "s1" is no longer pinned.
+ runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
+ assertEquals(0, mManager.getDynamicShortcuts().size());
+ assertShortcutIds(assertAllPinned(
+ mManager.getPinnedShortcuts()),
+ "s2", "s3");
+ });
+
+ installPackage(USER_0, CALLING_PACKAGE_3);
+ runWithCaller(CALLING_PACKAGE_3, USER_0, () -> {
+ assertEquals(0, mManager.getDynamicShortcuts().size());
+ assertEquals(0, mManager.getPinnedShortcuts().size());
+ });
+
+ runWithCaller(LAUNCHER_1, USER_0, () -> {
+ assertShortcutIds(assertAllPinned(
+ mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0))
+ /* empty */);
+ assertShortcutIds(assertAllPinned(
+ mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0))
+ /* empty */);
+ assertShortcutIds(assertAllPinned(
+ mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0))
+ /* empty */);
+ });
+ runWithCaller(LAUNCHER_2, USER_0, () -> {
+ assertShortcutIds(assertAllPinned(
+ mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0))
+ /* empty */);
+ assertShortcutIds(assertAllPinned(
+ mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0)),
+ "s2", "s3");
+ assertShortcutIds(assertAllPinned(
+ mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0))
+ /* empty */);
+ });
+ }
+
+ public void testSaveAndLoad_crossProfile() {
+ prepareCrossProfileDataSet();
+
+ dumpsysOnLogcat("Before save & load");
+
+ mService.saveDirtyInfo();
+ initService();
+
+ runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+ assertShortcutIds(assertAllDynamic(mManager.getDynamicShortcuts()),
+ "s1", "s2", "s3");
+ assertShortcutIds(assertAllPinned(mManager.getPinnedShortcuts()),
+ "s1", "s2", "s3", "s4");
+ });
+ runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
+ assertShortcutIds(assertAllDynamic(mManager.getDynamicShortcuts()),
+ "s1", "s2", "s3");
+ assertShortcutIds(assertAllPinned(mManager.getPinnedShortcuts()),
+ "s1", "s2", "s3", "s4", "s5");
+ });
+ runWithCaller(CALLING_PACKAGE_3, USER_0, () -> {
+ assertShortcutIds(assertAllDynamic(mManager.getDynamicShortcuts()),
+ "s1", "s2", "s3");
+ assertShortcutIds(assertAllPinned(mManager.getPinnedShortcuts()),
+ "s1", "s2", "s3", "s4", "s5", "s6");
+ });
+ runWithCaller(CALLING_PACKAGE_4, USER_0, () -> {
+ assertShortcutIds(assertAllDynamic(mManager.getDynamicShortcuts())
+ /* empty */);
+ assertShortcutIds(assertAllPinned(mManager.getPinnedShortcuts())
+ /* empty */);
+ });
+ runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
+ assertShortcutIds(assertAllDynamic(mManager.getDynamicShortcuts()),
+ "s1", "s2", "s3");
+ assertShortcutIds(assertAllPinned(mManager.getPinnedShortcuts()),
+ "s1", "s2", "s3", "s4", "s5", "s6");
+ });
+ runWithCaller(CALLING_PACKAGE_2, USER_P0, () -> {
+ assertShortcutIds(assertAllDynamic(mManager.getDynamicShortcuts())
+ /* empty */);
+ assertShortcutIds(assertAllPinned(mManager.getPinnedShortcuts())
+ /* empty */);
+ });
+ runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
+ assertShortcutIds(assertAllDynamic(mManager.getDynamicShortcuts()),
+ "x1", "x2", "x3");
+ assertShortcutIds(assertAllPinned(mManager.getPinnedShortcuts()),
+ "x4", "x5");
+ });
+ runWithCaller(LAUNCHER_1, USER_0, () -> {
+ assertShortcutIds(
+ mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_1), HANDLE_USER_0),
+ "s1");
+ assertShortcutIds(
+ mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_2), HANDLE_USER_0),
+ "s1", "s2");
+ assertShortcutIds(
+ mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_3), HANDLE_USER_0),
+ "s1", "s2", "s3");
+ assertShortcutIds(
+ mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_4), HANDLE_USER_0)
+ /* empty */);
+ assertShortcutIds(
+ mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_1), HANDLE_USER_P0),
+ "s1", "s4");
+ assertShortcutIds(
+ mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_2), HANDLE_USER_P0)
+ /* empty */);
+ TestUtils.assertExpectException(
+ SecurityException.class, "", () -> {
+ mLauncherApps.getShortcuts(
+ buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_10);
+ });
+ });
+ runWithCaller(LAUNCHER_2, USER_0, () -> {
+ assertShortcutIds(
+ mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_1), HANDLE_USER_0),
+ "s2");
+ assertShortcutIds(
+ mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_2), HANDLE_USER_0),
+ "s2", "s3");
+ assertShortcutIds(
+ mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_3), HANDLE_USER_0),
+ "s2", "s3", "s4");
+ assertShortcutIds(
+ mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_4), HANDLE_USER_0)
+ /* empty */);
+ assertShortcutIds(
+ mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_1), HANDLE_USER_P0),
+ "s2", "s5");
+ assertShortcutIds(
+ mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_2), HANDLE_USER_P0)
+ /* empty */);
+ });
+ runWithCaller(LAUNCHER_3, USER_0, () -> {
+ assertShortcutIds(
+ mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_1), HANDLE_USER_0),
+ "s3");
+ assertShortcutIds(
+ mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_2), HANDLE_USER_0),
+ "s3", "s4");
+ assertShortcutIds(
+ mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_3), HANDLE_USER_0),
+ "s3", "s4", "s5");
+ assertShortcutIds(
+ mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_4), HANDLE_USER_0)
+ /* empty */);
+ assertShortcutIds(
+ mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_1), HANDLE_USER_P0),
+ "s3", "s6");
+ assertShortcutIds(
+ mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_2), HANDLE_USER_P0)
+ /* empty */);
+ });
+ runWithCaller(LAUNCHER_4, USER_0, () -> {
+ assertShortcutIds(
+ mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_1), HANDLE_USER_0)
+ /* empty */);
+ assertShortcutIds(
+ mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_2), HANDLE_USER_0)
+ /* empty */);
+ assertShortcutIds(
+ mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_3), HANDLE_USER_0)
+ /* empty */);
+ assertShortcutIds(
+ mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_4), HANDLE_USER_0)
+ /* empty */);
+ assertShortcutIds(
+ mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_1), HANDLE_USER_P0)
+ /* empty */);
+ assertShortcutIds(
+ mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_2), HANDLE_USER_P0)
+ /* empty */);
+ });
+ runWithCaller(LAUNCHER_1, USER_P0, () -> {
+ assertShortcutIds(
+ mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_1), HANDLE_USER_0),
+ "s3", "s4");
+ assertShortcutIds(
+ mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_2), HANDLE_USER_0),
+ "s3", "s4", "s5");
+ assertShortcutIds(
+ mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_3), HANDLE_USER_0),
+ "s3", "s4", "s5", "s6");
+ assertShortcutIds(
+ mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_1), HANDLE_USER_P0),
+ "s1", "s4");
+ TestUtils.assertExpectException(
+ SecurityException.class, "unrelated profile", () -> {
+ mLauncherApps.getShortcuts(
+ buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_10);
+ });
+ });
+ runWithCaller(LAUNCHER_1, USER_10, () -> {
+ assertShortcutIds(
+ mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_1), HANDLE_USER_10),
+ "x4", "x5");
+ assertShortcutIds(
+ mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_2), HANDLE_USER_10)
+ /* empty */);
+ assertShortcutIds(
+ mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_3), HANDLE_USER_10)
+ /* empty */);
+ TestUtils.assertExpectException(
+ SecurityException.class, "unrelated profile", () -> {
+ mLauncherApps.getShortcuts(
+ buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0);
+ });
+ TestUtils.assertExpectException(
+ SecurityException.class, "unrelated profile", () -> {
+ mLauncherApps.getShortcuts(
+ buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_P0);
+ });
+ });
+ }
+
+ // ShortcutInfo tests
+
+ public void testShortcutInfoMissingMandatoryFields() {
+ TestUtils.assertExpectException(
+ IllegalArgumentException.class,
+ "ID must be provided",
+ () -> new ShortcutInfo.Builder(getTestContext()).build());
+ TestUtils.assertExpectException(
+ IllegalArgumentException.class,
+ "title must be provided",
+ () -> new ShortcutInfo.Builder(getTestContext()).setId("id").build()
+ .enforceMandatoryFields());
+ TestUtils.assertExpectException(
+ NullPointerException.class,
+ "Intent must be provided",
+ () -> new ShortcutInfo.Builder(getTestContext()).setId("id").setTitle("x").build()
+ .enforceMandatoryFields());
+ }
+
+ public void testShortcutInfoParcel() {
+ ShortcutInfo si = parceled(new ShortcutInfo.Builder(getTestContext())
+ .setId("id")
+ .setTitle("title")
+ .setIntent(makeIntent("action", ShortcutActivity.class))
+ .build());
+ assertEquals(getTestContext().getPackageName(), si.getPackageName());
+ assertEquals("id", si.getId());
+ assertEquals("title", si.getTitle());
+ assertEquals("action", si.getIntent().getAction());
+
+ PersistableBundle pb = new PersistableBundle();
+ pb.putInt("k", 1);
+
+ si = new ShortcutInfo.Builder(getTestContext())
+ .setId("id")
+ .setActivityComponent(new ComponentName("a", "b"))
+ .setIcon(Icon.createWithContentUri("content://a.b.c/"))
+ .setTitle("title")
+ .setText("text")
+ .setIntent(makeIntent("action", ShortcutActivity.class, "key", "val"))
+ .setWeight(123)
+ .setExtras(pb)
+ .build();
+ si.addFlags(ShortcutInfo.FLAG_PINNED);
+ si.setBitmapPath("abc");
+ si.setIconResourceId(456);
+
+ si = parceled(si);
+
+ assertEquals(getTestContext().getPackageName(), si.getPackageName());
+ assertEquals("id", si.getId());
+ assertEquals(new ComponentName("a", "b"), si.getActivityComponent());
+ assertEquals("content://a.b.c/", si.getIcon().getUriString());
+ assertEquals("title", si.getTitle());
+ assertEquals("text", si.getText());
+ assertEquals("action", si.getIntent().getAction());
+ assertEquals("val", si.getIntent().getStringExtra("key"));
+ assertEquals(123, si.getWeight());
+ assertEquals(1, si.getExtras().getInt("k"));
+
+ assertEquals(ShortcutInfo.FLAG_PINNED, si.getFlags());
+ assertEquals("abc", si.getBitmapPath());
+ assertEquals(456, si.getIconResourceId());
+ }
+
+ public void testShortcutInfoClone() {
+ PersistableBundle pb = new PersistableBundle();
+ pb.putInt("k", 1);
+ ShortcutInfo sorig = new ShortcutInfo.Builder(getTestContext())
+ .setId("id")
+ .setActivityComponent(new ComponentName("a", "b"))
+ .setIcon(Icon.createWithContentUri("content://a.b.c/"))
+ .setTitle("title")
+ .setText("text")
+ .setIntent(makeIntent("action", ShortcutActivity.class, "key", "val"))
+ .setWeight(123)
+ .setExtras(pb)
+ .build();
+ sorig.addFlags(ShortcutInfo.FLAG_PINNED);
+ sorig.setBitmapPath("abc");
+ sorig.setIconResourceId(456);
+
+ ShortcutInfo si = sorig.clone(/* clone flags*/ 0);
+
+ assertEquals(getTestContext().getPackageName(), si.getPackageName());
+ assertEquals("id", si.getId());
+ assertEquals(new ComponentName("a", "b"), si.getActivityComponent());
+ assertEquals("content://a.b.c/", si.getIcon().getUriString());
+ assertEquals("title", si.getTitle());
+ assertEquals("text", si.getText());
+ assertEquals("action", si.getIntent().getAction());
+ assertEquals("val", si.getIntent().getStringExtra("key"));
+ assertEquals(123, si.getWeight());
+ assertEquals(1, si.getExtras().getInt("k"));
+
+ assertEquals(ShortcutInfo.FLAG_PINNED, si.getFlags());
+ assertEquals("abc", si.getBitmapPath());
+ assertEquals(456, si.getIconResourceId());
+
+ si = sorig.clone(ShortcutInfo.CLONE_REMOVE_FOR_CREATOR);
+
+ assertEquals(getTestContext().getPackageName(), si.getPackageName());
+ assertEquals("id", si.getId());
+ assertEquals(new ComponentName("a", "b"), si.getActivityComponent());
+ assertEquals(null, si.getIcon());
+ assertEquals("title", si.getTitle());
+ assertEquals("text", si.getText());
+ assertEquals("action", si.getIntent().getAction());
+ assertEquals("val", si.getIntent().getStringExtra("key"));
+ assertEquals(123, si.getWeight());
+ assertEquals(1, si.getExtras().getInt("k"));
+
+ assertEquals(ShortcutInfo.FLAG_PINNED, si.getFlags());
+ assertEquals(null, si.getBitmapPath());
+ assertEquals(0, si.getIconResourceId());
+
+ si = sorig.clone(ShortcutInfo.CLONE_REMOVE_FOR_LAUNCHER);
+
+ assertEquals(getTestContext().getPackageName(), si.getPackageName());
+ assertEquals("id", si.getId());
+ assertEquals(new ComponentName("a", "b"), si.getActivityComponent());
+ assertEquals(null, si.getIcon());
+ assertEquals("title", si.getTitle());
+ assertEquals("text", si.getText());
+ assertEquals(null, si.getIntent());
+ assertEquals(123, si.getWeight());
+ assertEquals(1, si.getExtras().getInt("k"));
+
+ assertEquals(ShortcutInfo.FLAG_PINNED, si.getFlags());
+ assertEquals(null, si.getBitmapPath());
+ assertEquals(0, si.getIconResourceId());
+
+ si = sorig.clone(ShortcutInfo.CLONE_REMOVE_NON_KEY_INFO);
+
+ assertEquals(getTestContext().getPackageName(), si.getPackageName());
+ assertEquals("id", si.getId());
+ assertEquals(null, si.getActivityComponent());
+ assertEquals(null, si.getIcon());
+ assertEquals(null, si.getTitle());
+ assertEquals(null, si.getText());
+ assertEquals(null, si.getIntent());
+ assertEquals(0, si.getWeight());
+ assertEquals(null, si.getExtras());
+
+ assertEquals(ShortcutInfo.FLAG_PINNED | ShortcutInfo.FLAG_KEY_FIELDS_ONLY, si.getFlags());
+ assertEquals(null, si.getBitmapPath());
+ assertEquals(0, si.getIconResourceId());
+ }
+
+ public void testShortcutInfoCopyNonNullFieldsFrom() throws InterruptedException {
+ PersistableBundle pb = new PersistableBundle();
+ pb.putInt("k", 1);
+ ShortcutInfo sorig = new ShortcutInfo.Builder(getTestContext())
+ .setId("id")
+ .setActivityComponent(new ComponentName("a", "b"))
+ .setIcon(Icon.createWithContentUri("content://a.b.c/"))
+ .setTitle("title")
+ .setText("text")
+ .setIntent(makeIntent("action", ShortcutActivity.class, "key", "val"))
+ .setWeight(123)
+ .setExtras(pb)
+ .build();
+ sorig.addFlags(ShortcutInfo.FLAG_PINNED);
+ sorig.setBitmapPath("abc");
+ sorig.setIconResourceId(456);
+
+ ShortcutInfo si;
+
+ si = sorig.clone(/* flags=*/ 0);
+ si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
+ .setActivityComponent(new ComponentName("x", "y")).build());
+ assertEquals(new ComponentName("x", "y"), si.getActivityComponent());
+
+ si = sorig.clone(/* flags=*/ 0);
+ si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
+ .setIcon(Icon.createWithContentUri("content://x.y.z/")).build());
+ assertEquals("content://x.y.z/", si.getIcon().getUriString());
+
+ si = sorig.clone(/* flags=*/ 0);
+ si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
+ .setTitle("xyz").build());
+ assertEquals("xyz", si.getTitle());
+
+ si = sorig.clone(/* flags=*/ 0);
+ si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
+ .setText("xxx").build());
+ assertEquals("xxx", si.getText());
+
+ si = sorig.clone(/* flags=*/ 0);
+ si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
+ .setIntent(makeIntent("action2", ShortcutActivity.class)).build());
+ assertEquals("action2", si.getIntent().getAction());
+ assertEquals(null, si.getIntent().getStringExtra("key"));
+
+ si = sorig.clone(/* flags=*/ 0);
+ si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
+ .setIntent(makeIntent("action3", ShortcutActivity.class, "key", "x")).build());
+ assertEquals("action3", si.getIntent().getAction());
+ assertEquals("x", si.getIntent().getStringExtra("key"));
+
+ si = sorig.clone(/* flags=*/ 0);
+ si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
+ .setWeight(999).build());
+ assertEquals(999, si.getWeight());
+
+
+ PersistableBundle pb2 = new PersistableBundle();
+ pb2.putInt("x", 99);
+
+ si = sorig.clone(/* flags=*/ 0);
+ si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
+ .setExtras(pb2).build());
+ assertEquals(99, si.getExtras().getInt("x"));
+
+ final long timestamp = si.getLastChangedTimestamp();
+ Thread.sleep(2);
+
+ si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
+ .setTitle("xyz").build());
+
+ assertTrue(si.getLastChangedTimestamp() > timestamp);
+ }
+
+ public void testShortcutInfoSaveAndLoad() throws InterruptedException {
+ setCaller(CALLING_PACKAGE_1, USER_0);
+
+ final Icon bmp32x32 = Icon.createWithBitmap(BitmapFactory.decodeResource(
+ getTestContext().getResources(), R.drawable.black_32x32));
+
+ PersistableBundle pb = new PersistableBundle();
+ pb.putInt("k", 1);
+ ShortcutInfo sorig = new ShortcutInfo.Builder(mClientContext)
+ .setId("id")
+ .setActivityComponent(new ComponentName(mClientContext, ShortcutActivity2.class))
+ .setIcon(bmp32x32)
+ .setTitle("title")
+ .setText("text")
+ .setIntent(makeIntent("action", ShortcutActivity.class, "key", "val"))
+ .setWeight(123)
+ .setExtras(pb)
+ .build();
+
+ mManager.addDynamicShortcut(sorig);
+
+ Thread.sleep(2);
+ final long now = System.currentTimeMillis();
+
+ // Save and load.
+ mService.saveDirtyInfo();
+ initService();
+ mService.handleUnlockUser(USER_0);
+
+ ShortcutInfo si;
+ si = mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "id", USER_0);
+
+ assertEquals(CALLING_PACKAGE_1, si.getPackageName());
+ assertEquals("id", si.getId());
+ assertEquals(ShortcutActivity2.class.getName(), si.getActivityComponent().getClassName());
+ assertEquals(null, si.getIcon());
+ assertEquals("title", si.getTitle());
+ assertEquals("text", si.getText());
+ assertEquals("action", si.getIntent().getAction());
+ assertEquals("val", si.getIntent().getStringExtra("key"));
+ assertEquals(123, si.getWeight());
+ assertEquals(1, si.getExtras().getInt("k"));
+
+ assertEquals(ShortcutInfo.FLAG_DYNAMIC | ShortcutInfo.FLAG_HAS_ICON_FILE, si.getFlags());
+ assertNotNull(si.getBitmapPath()); // Something should be set.
+ assertEquals(0, si.getIconResourceId());
+ assertTrue(si.getLastChangedTimestamp() < now);
+ }
+
+ public void testShortcutInfoSaveAndLoad_forBackup() {
+ setCaller(CALLING_PACKAGE_1, USER_0);
+
+ final Icon bmp32x32 = Icon.createWithBitmap(BitmapFactory.decodeResource(
+ getTestContext().getResources(), R.drawable.black_32x32));
+
+ PersistableBundle pb = new PersistableBundle();
+ pb.putInt("k", 1);
+ ShortcutInfo sorig = new ShortcutInfo.Builder(mClientContext)
+ .setId("id")
+ .setActivityComponent(new ComponentName(mClientContext, ShortcutActivity2.class))
+ .setIcon(bmp32x32)
+ .setTitle("title")
+ .setText("text")
+ .setIntent(makeIntent("action", ShortcutActivity.class, "key", "val"))
+ .setWeight(123)
+ .setExtras(pb)
+ .build();
+
+ mManager.addDynamicShortcut(sorig);
+
+ // Dynamic shortcuts won't be backed up, so we need to pin it.
+ setCaller(LAUNCHER_1, USER_0);
+ mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("id"), HANDLE_USER_0);
+
+ // Do backup & restore.
+ backupAndRestore();
+
+ ShortcutInfo si;
+ si = mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "id", USER_0);
+
+ assertEquals(CALLING_PACKAGE_1, si.getPackageName());
+ assertEquals("id", si.getId());
+ assertEquals(ShortcutActivity2.class.getName(), si.getActivityComponent().getClassName());
+ assertEquals(null, si.getIcon());
+ assertEquals("title", si.getTitle());
+ assertEquals("text", si.getText());
+ assertEquals("action", si.getIntent().getAction());
+ assertEquals("val", si.getIntent().getStringExtra("key"));
+ assertEquals(123, si.getWeight());
+ assertEquals(1, si.getExtras().getInt("k"));
+
+ assertEquals(ShortcutInfo.FLAG_PINNED, si.getFlags());
+ assertNull(si.getBitmapPath()); // No icon.
+ assertEquals(0, si.getIconResourceId());
+ }
+
+ public void testDumpsys_crossProfile() {
+ prepareCrossProfileDataSet();
+ dumpsysOnLogcat("test1", /* force= */ true);
+ }
+
+ public void testDumpsys_withIcons() {
+ testIcons();
+ // Dump after having some icons.
+ dumpsysOnLogcat("test1", /* force= */ true);
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/pm/backup/BackupUtilsTest.java b/services/tests/servicestests/src/com/android/server/pm/backup/BackupUtilsTest.java
new file mode 100644
index 0000000..c016e61
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/pm/backup/BackupUtilsTest.java
@@ -0,0 +1,118 @@
+/*
+ * 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.backup;
+
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageParser.Package;
+import android.content.pm.Signature;
+import android.test.AndroidTestCase;
+import android.test.MoreAsserts;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import com.android.server.backup.BackupUtils;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+
+@SmallTest
+public class BackupUtilsTest extends AndroidTestCase {
+
+ private Signature[] genSignatures(String... signatures) {
+ final Signature[] sigs = new Signature[signatures.length];
+ for (int i = 0; i < signatures.length; i++){
+ sigs[i] = new Signature(signatures[i].getBytes());
+ }
+ return sigs;
+ }
+
+ private PackageInfo genPackage(String... signatures) {
+ final PackageInfo pi = new PackageInfo();
+ pi.packageName = "package";
+ pi.applicationInfo = new ApplicationInfo();
+ pi.signatures = genSignatures(signatures);
+
+ return pi;
+ }
+
+ public void testSignaturesMatch() {
+ final ArrayList<byte[]> stored1 = BackupUtils.hashSignatureArray(Arrays.asList(
+ "abc".getBytes()));
+ final ArrayList<byte[]> stored2 = BackupUtils.hashSignatureArray(Arrays.asList(
+ "abc".getBytes(), "def".getBytes()));
+
+ PackageInfo pi;
+
+ // False for null package.
+ assertFalse(BackupUtils.signaturesMatch(stored1, null));
+
+ // If it's a system app, signatures don't matter.
+ pi = genPackage("xyz");
+ pi.applicationInfo.flags |= ApplicationInfo.FLAG_SYSTEM;
+ assertTrue(BackupUtils.signaturesMatch(stored1, pi));
+
+ // Non system apps.
+ assertTrue(BackupUtils.signaturesMatch(stored1, genPackage("abc")));
+
+ // Superset is okay.
+ assertTrue(BackupUtils.signaturesMatch(stored1, genPackage("abc", "xyz")));
+ assertTrue(BackupUtils.signaturesMatch(stored1, genPackage("xyz", "abc")));
+
+ assertFalse(BackupUtils.signaturesMatch(stored1, genPackage("xyz")));
+ assertFalse(BackupUtils.signaturesMatch(stored1, genPackage("xyz", "def")));
+
+ assertTrue(BackupUtils.signaturesMatch(stored2, genPackage("def", "abc")));
+ assertTrue(BackupUtils.signaturesMatch(stored2, genPackage("x", "def", "abc", "y")));
+
+ // Subset is not okay.
+ assertFalse(BackupUtils.signaturesMatch(stored2, genPackage("abc")));
+ assertFalse(BackupUtils.signaturesMatch(stored2, genPackage("def")));
+ }
+
+ public void testHashSignature() {
+ final byte[] sig1 = "abc".getBytes();
+ final byte[] sig2 = "def".getBytes();
+
+ final byte[] hash1a = BackupUtils.hashSignature(sig1);
+ final byte[] hash1b = BackupUtils.hashSignature(new Signature(sig1));
+
+ final byte[] hash2a = BackupUtils.hashSignature(sig2);
+ final byte[] hash2b = BackupUtils.hashSignature(new Signature(sig2));
+
+ assertEquals(32, hash1a.length);
+ MoreAsserts.assertEquals(hash1a, hash1b);
+
+ assertEquals(32, hash2a.length);
+ MoreAsserts.assertEquals(hash2a, hash2b);
+
+ assertFalse(Arrays.equals(hash1a, hash2a));
+
+ final ArrayList<byte[]> listA = BackupUtils.hashSignatureArray(Arrays.asList(
+ "abc".getBytes(), "def".getBytes()));
+
+ final ArrayList<byte[]> listB = BackupUtils.hashSignatureArray(new Signature[]{
+ new Signature("abc".getBytes()), new Signature("def".getBytes())});
+
+ assertEquals(2, listA.size());
+ assertEquals(2, listB.size());
+
+ MoreAsserts.assertEquals(hash1a, listA.get(0));
+ MoreAsserts.assertEquals(hash1a, listB.get(0));
+
+ MoreAsserts.assertEquals(hash2a, listA.get(1));
+ MoreAsserts.assertEquals(hash2a, listB.get(1));
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/testutis/TestUtils.java b/services/tests/servicestests/src/com/android/server/testutis/TestUtils.java
index 52e8f37..d2a4484 100644
--- a/services/tests/servicestests/src/com/android/server/testutis/TestUtils.java
+++ b/services/tests/servicestests/src/com/android/server/testutis/TestUtils.java
@@ -24,19 +24,14 @@
}
public static void assertExpectException(Class<? extends Throwable> expectedExceptionType,
- Runnable r) {
- assertExpectException(expectedExceptionType, null, r);
- }
-
- public static void assertExpectException(Class<? extends Throwable> expectedExceptionType,
String expectedExceptionMessageRegex, Runnable r) {
try {
r.run();
- Assert.fail("Expected exception type " + expectedExceptionType.getClass().getName()
+ Assert.fail("Expected exception type " + expectedExceptionType.getName()
+ " was not thrown");
} catch (Throwable e) {
Assert.assertTrue(
- "Expected exception type was " + expectedExceptionType.getClass().getName()
+ "Expected exception type was " + expectedExceptionType.getName()
+ " but caught " + e.getClass().getName(),
expectedExceptionType.isAssignableFrom(e.getClass()));
if (expectedExceptionMessageRegex != null) {
diff --git a/services/usb/java/com/android/server/usb/UsbAlsaManager.java b/services/usb/java/com/android/server/usb/UsbAlsaManager.java
index 129e537..058de05 100644
--- a/services/usb/java/com/android/server/usb/UsbAlsaManager.java
+++ b/services/usb/java/com/android/server/usb/UsbAlsaManager.java
@@ -385,6 +385,7 @@
UsbAudioDevice audioDevice = selectAudioCard(addedCard);
if (audioDevice != null) {
mAudioDevices.put(usbDevice, audioDevice);
+ Slog.i(TAG, "USB Audio Device Added: " + audioDevice);
}
// look for MIDI devices
@@ -441,6 +442,7 @@
}
UsbAudioDevice audioDevice = mAudioDevices.remove(usbDevice);
+ Slog.i(TAG, "USB Audio Device Removed: " + audioDevice);
if (audioDevice != null) {
if (audioDevice.mHasPlayback || audioDevice.mHasCapture) {
notifyDeviceState(audioDevice, false);
diff --git a/telecomm/java/android/telecom/Conference.java b/telecomm/java/android/telecom/Conference.java
index 06851ee..1ce4ade 100644
--- a/telecomm/java/android/telecom/Conference.java
+++ b/telecomm/java/android/telecom/Conference.java
@@ -694,7 +694,7 @@
if (mPreviousExtraKeys != null) {
List<String> toRemove = new ArrayList<String>();
for (String oldKey : mPreviousExtraKeys) {
- if (!extras.containsKey(oldKey)) {
+ if (extras == null || !extras.containsKey(oldKey)) {
toRemove.add(oldKey);
}
}
@@ -710,7 +710,9 @@
mPreviousExtraKeys = new ArraySet<String>();
}
mPreviousExtraKeys.clear();
- mPreviousExtraKeys.addAll(extras.keySet());
+ if (extras != null) {
+ mPreviousExtraKeys.addAll(extras.keySet());
+ }
}
/**
diff --git a/telecomm/java/android/telecom/Connection.java b/telecomm/java/android/telecom/Connection.java
index 310c957..d83cdb8 100644
--- a/telecomm/java/android/telecom/Connection.java
+++ b/telecomm/java/android/telecom/Connection.java
@@ -1887,7 +1887,7 @@
if (mPreviousExtraKeys != null) {
List<String> toRemove = new ArrayList<String>();
for (String oldKey : mPreviousExtraKeys) {
- if (!extras.containsKey(oldKey)) {
+ if (extras == null || !extras.containsKey(oldKey)) {
toRemove.add(oldKey);
}
}
@@ -1902,7 +1902,9 @@
mPreviousExtraKeys = new ArraySet<String>();
}
mPreviousExtraKeys.clear();
- mPreviousExtraKeys.addAll(extras.keySet());
+ if (extras != null) {
+ mPreviousExtraKeys.addAll(extras.keySet());
+ }
}
/**
@@ -2317,7 +2319,7 @@
*/
public void sendConnectionEvent(String event, Bundle extras) {
for (Listener l : mListeners) {
- l.onConnectionEvent(this, event, null);
+ l.onConnectionEvent(this, event, extras);
}
}
}
diff --git a/telecomm/java/android/telecom/PhoneAccount.java b/telecomm/java/android/telecom/PhoneAccount.java
index b56ce73..dbc2b0c 100644
--- a/telecomm/java/android/telecom/PhoneAccount.java
+++ b/telecomm/java/android/telecom/PhoneAccount.java
@@ -170,6 +170,15 @@
public static final int CAPABILITY_VIDEO_CALLING_RELIES_ON_PRESENCE = 0x100;
/**
+ * Flag indicating that for this {@link PhoneAccount}, emergency video calling is allowed.
+ * <p>
+ * When set, Telecom will allow emergency video calls to be placed. When not set, Telecom will
+ * convert all outgoing video calls to emergency numbers to audio-only.
+ * @hide
+ */
+ public static final int CAPABILITY_EMERGENCY_VIDEO_CALLING = 0x200;
+
+ /**
* URI scheme for telephone number URIs.
*/
public static final String SCHEME_TEL = "tel";
@@ -731,6 +740,9 @@
if (hasCapabilities(CAPABILITY_PLACE_EMERGENCY_CALLS)) {
sb.append("PlaceEmerg ");
}
+ if (hasCapabilities(CAPABILITY_EMERGENCY_VIDEO_CALLING)) {
+ sb.append("EmergVideo ");
+ }
if (hasCapabilities(CAPABILITY_SIM_SUBSCRIPTION)) {
sb.append("SimSub ");
}
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index c69a360..461611d 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -252,6 +252,16 @@
public static final String KEY_CARRIER_WFC_IMS_AVAILABLE_BOOL = "carrier_wfc_ims_available_bool";
/**
+ * Flag specifying whether WFC over IMS supports the "wifi only" option. If false, the wifi
+ * calling settings will not include an option for "wifi only". If true, the wifi calling
+ * settings will include an option for "wifi only"
+ * <p>
+ * By default, it is assumed that WFC supports "wifi only".
+ */
+ public static final String KEY_CARRIER_WFC_SUPPORTS_WIFI_ONLY_BOOL =
+ "carrier_wfc_supports_wifi_only_bool";
+
+ /**
* Default WFC_IMS_mode 0: WIFI_ONLY
* 1: CELLULAR_PREFERRED
* 2: WIFI_PREFERRED
@@ -628,6 +638,7 @@
sDefaults.putBoolean(KEY_CARRIER_VOLTE_AVAILABLE_BOOL, false);
sDefaults.putBoolean(KEY_CARRIER_VT_AVAILABLE_BOOL, false);
sDefaults.putBoolean(KEY_CARRIER_WFC_IMS_AVAILABLE_BOOL, false);
+ sDefaults.putBoolean(KEY_CARRIER_WFC_SUPPORTS_WIFI_ONLY_BOOL, true);
sDefaults.putBoolean(KEY_CARRIER_DEFAULT_WFC_IMS_ENABLED_BOOL, false);
sDefaults.putBoolean(KEY_CARRIER_DEFAULT_WFC_IMS_ROAMING_ENABLED_BOOL, false);
sDefaults.putInt(KEY_CARRIER_DEFAULT_WFC_IMS_MODE_INT, 2);
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index b482811..865af78 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -3550,7 +3550,7 @@
* @return the response of ISIM Authetification, or null if not available
* @hide
* @deprecated
- * @see getIccSimChallengeResponse with appType=PhoneConstants.APPTYPE_ISIM
+ * @see getIccAuthentication with appType=PhoneConstants.APPTYPE_ISIM
*/
public String getIsimChallengeResponse(String nonce){
try {
@@ -3566,21 +3566,60 @@
}
}
+ // ICC SIM Application Types
+ public static final int APPTYPE_SIM = PhoneConstants.APPTYPE_SIM;
+ public static final int APPTYPE_USIM = PhoneConstants.APPTYPE_USIM;
+ public static final int APPTYPE_RUIM = PhoneConstants.APPTYPE_RUIM;
+ public static final int APPTYPE_CSIM = PhoneConstants.APPTYPE_CSIM;
+ public static final int APPTYPE_ISIM = PhoneConstants.APPTYPE_ISIM;
+ // authContext (parameter P2) when doing SIM challenge,
+ // per 3GPP TS 31.102 (Section 7.1.2)
+ public static final int AUTHTYPE_EAP_SIM = PhoneConstants.AUTH_CONTEXT_EAP_SIM;
+ public static final int AUTHTYPE_EAP_AKA = PhoneConstants.AUTH_CONTEXT_EAP_AKA;
+
/**
- * Returns the response of SIM Authentication through RIL.
- * Returns null if the Authentication hasn't been successful
- * @param subId subscription ID to be queried
- * @param appType ICC application type (@see com.android.internal.telephony.PhoneConstants#APPTYPE_xxx)
- * @param data authentication challenge data
- * @return the response of SIM Authentication, or null if not available
- * @hide
+ * Returns the response of authentication for the default subscription.
+ * Returns null if the authentication hasn't been successful
+ *
+ * <p>Requires that the calling app has carrier privileges or READ_PRIVILEGED_PHONE_STATE
+ * permission.
+ *
+ * @param appType the icc application type, like {@link #APPTYPE_USIM}
+ * @param authType the authentication type, {@link #AUTHTYPE_EAP_AKA} or
+ * {@link #AUTHTYPE_EAP_SIM}
+ * @param data authentication challenge data, base64 encoded.
+ * See 3GPP TS 31.102 7.1.2 for more details.
+ * @return the response of authentication, or null if not available
+ *
+ * @see #hasCarrierPrivileges
*/
- public String getIccSimChallengeResponse(int subId, int appType, String data) {
+ public String getIccAuthentication(int appType, int authType, String data) {
+ return getIccAuthentication(getDefaultSubscription(), appType, authType, data);
+ }
+
+ /**
+ * Returns the response of USIM Authentication for specified subId.
+ * Returns null if the authentication hasn't been successful
+ *
+ * <p>Requires that the calling app has carrier privileges.
+ *
+ * @param subId subscription ID used for authentication
+ * @param appType the icc application type, like {@link #APPTYPE_USIM}
+ * @param authType the authentication type, {@link #AUTHTYPE_EAP_AKA} or
+ * {@link #AUTHTYPE_EAP_SIM}
+ * @param data authentication challenge data, base64 encoded.
+ * See 3GPP TS 31.102 7.1.2 for more details.
+ * @return the response of authentication, or null if not available
+ *
+ * @see #hasCarrierPrivileges
+ */
+
+ public String getIccAuthentication(int subId, int appType, int authType, String data) {
try {
IPhoneSubInfo info = getSubscriberInfo();
if (info == null)
return null;
- return info.getIccSimChallengeResponse(subId, appType, data);
+ return info.getIccSimChallengeResponse(subId, appType, authType, data);
} catch (RemoteException ex) {
return null;
} catch (NullPointerException ex) {
@@ -3599,9 +3638,10 @@
* @param appType ICC application type (@see com.android.internal.telephony.PhoneConstants#APPTYPE_xxx)
* @param data authentication challenge data
* @return the response of SIM Authentication, or null if not available
+ * @hide
*/
public String getIccSimChallengeResponse(int appType, String data) {
- return getIccSimChallengeResponse(getDefaultSubscription(), appType, data);
+ return getIccAuthentication(getDefaultSubscription(), appType, AUTHTYPE_EAP_SIM, data);
}
/**
diff --git a/telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl b/telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl
index dc2b297..02baa34 100644
--- a/telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl
+++ b/telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl
@@ -196,8 +196,9 @@
*
* @param subId subscription ID to be queried
* @param appType ICC application type (@see com.android.internal.telephony.PhoneConstants#APPTYPE_xxx)
+ * @param authType Authentication type, see PhoneConstants#AUTHTYPE_xxx
* @param data authentication challenge data
* @return challenge response
*/
- String getIccSimChallengeResponse(int subId, int appType, String data);
+ String getIccSimChallengeResponse(int subId, int appType, int authType, String data);
}
diff --git a/telephony/java/com/android/internal/telephony/PhoneConstants.java b/telephony/java/com/android/internal/telephony/PhoneConstants.java
index ecd89ed..1680fe3 100644
--- a/telephony/java/com/android/internal/telephony/PhoneConstants.java
+++ b/telephony/java/com/android/internal/telephony/PhoneConstants.java
@@ -202,4 +202,10 @@
public static final int AUDIO_OUTPUT_ENABLE_SPEAKER = 0;
public static final int AUDIO_OUTPUT_DISABLE_SPEAKER = 1;
public static final int AUDIO_OUTPUT_DEFAULT = AUDIO_OUTPUT_ENABLE_SPEAKER;
+
+ // authContext (parameter P2) when doing SIM challenge,
+ // per 3GPP TS 31.102 (Section 7.1.2)
+ public static final int AUTH_CONTEXT_EAP_SIM = 128;
+ public static final int AUTH_CONTEXT_EAP_AKA = 129;
+ public static final int AUTH_CONTEXT_UNDEFINED = -1;
}
diff --git a/test-runner/src/android/test/mock/MockContext.java b/test-runner/src/android/test/mock/MockContext.java
index b739ead..c7cbf97 100644
--- a/test-runner/src/android/test/mock/MockContext.java
+++ b/test-runner/src/android/test/mock/MockContext.java
@@ -145,6 +145,7 @@
throw new UnsupportedOperationException();
}
+ /** @removed */
@Override
public SharedPreferences getSharedPreferences(File file, int mode) {
throw new UnsupportedOperationException();
@@ -180,6 +181,7 @@
throw new UnsupportedOperationException();
}
+ /** @removed */
@Override
public File getSharedPreferencesPath(String name) {
throw new UnsupportedOperationException();
diff --git a/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java b/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java
index ed7351f8..033312b 100644
--- a/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java
+++ b/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java
@@ -62,7 +62,7 @@
private static final String KEY_REQUIRED_ACCOUNTS = "required_accounts";
private static final String WEARABLE_ACTION_GOOGLE =
"com.google.android.wearable.action.GOOGLE";
- private static final int INITIAL_LAUNCH_IDLE_TIMEOUT = 7500; //7.5s to allow app to idle
+ private static final int INITIAL_LAUNCH_IDLE_TIMEOUT = 60000; //60s to allow app to idle
private static final int POST_LAUNCH_IDLE_TIMEOUT = 750; //750ms idle for non initial launches
private static final int BETWEEN_LAUNCH_SLEEP_TIMEOUT = 2000; //2s between launching apps
diff --git a/tests/LocationTracker/src/com/android/locationtracker/SettingsActivity.java b/tests/LocationTracker/src/com/android/locationtracker/SettingsActivity.java
index cb77118..a169b18 100644
--- a/tests/LocationTracker/src/com/android/locationtracker/SettingsActivity.java
+++ b/tests/LocationTracker/src/com/android/locationtracker/SettingsActivity.java
@@ -1,35 +1,35 @@
-/*
- * Copyright (C) 2008 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.locationtracker;
-
-import android.os.Bundle;
-import android.preference.PreferenceActivity;
-
-/**
- * Settings preference screen for location tracker
- */
-public class SettingsActivity extends PreferenceActivity {
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
-
- // Load the preferences from an XML resource
- addPreferencesFromResource(R.xml.preferences);
- }
-
-}
+/*
+ * Copyright (C) 2008 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.locationtracker;
+
+import android.os.Bundle;
+import android.preference.PreferenceActivity;
+
+/**
+ * Settings preference screen for location tracker
+ */
+public class SettingsActivity extends PreferenceActivity {
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ // Load the preferences from an XML resource
+ addPreferencesFromResource(R.xml.preferences);
+ }
+
+}
diff --git a/tests/LocationTracker/src/com/android/locationtracker/data/TrackerListHelper.java b/tests/LocationTracker/src/com/android/locationtracker/data/TrackerListHelper.java
index 55d4d1e..adc39b3 100644
--- a/tests/LocationTracker/src/com/android/locationtracker/data/TrackerListHelper.java
+++ b/tests/LocationTracker/src/com/android/locationtracker/data/TrackerListHelper.java
@@ -1,75 +1,75 @@
-/*
- * Copyright (C) 2008 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.locationtracker.data;
-
-import android.app.ListActivity;
-import android.content.Context;
-import android.database.Cursor;
-import android.view.View;
-import android.widget.ResourceCursorAdapter;
-import android.widget.TextView;
-
-import com.android.locationtracker.R;
-
-/**
- * Used to bind Tracker data to a list view UI
- */
-public class TrackerListHelper extends TrackerDataHelper {
-
- private ListActivity mActivity;
-
- // sort entries by most recent first
- private static final String SORT_ORDER = TrackerEntry.ID_COL + " DESC";
-
- public TrackerListHelper(ListActivity activity) {
- super(activity, TrackerDataHelper.CSV_FORMATTER);
- mActivity = activity;
- }
-
- /**
- * Helper method for binding the list activities UI to the tracker data
- * Tracker data will be sorted in most-recent first order
- * Will enable automatic UI changes as tracker data changes
- *
- * @param layout - layout to populate data
- */
- public void bindListUI(int layout) {
- Cursor cursor = mActivity.managedQuery(TrackerProvider.CONTENT_URI,
- TrackerEntry.ATTRIBUTES, null, null, SORT_ORDER);
- // Used to map tracker entries from the database to views
- TrackerAdapter adapter = new TrackerAdapter(mActivity, layout, cursor);
- mActivity.setListAdapter(adapter);
- cursor.setNotificationUri(mActivity.getContentResolver(),
- TrackerProvider.CONTENT_URI);
-
- }
-
- private class TrackerAdapter extends ResourceCursorAdapter {
-
- public TrackerAdapter(Context context, int layout, Cursor c) {
- super(context, layout, c);
- }
-
- @Override
- public void bindView(View view, Context context, Cursor cursor) {
- final TextView v = (TextView) view
- .findViewById(R.id.entrylist_item);
- String rowText = mFormatter.getOutput(TrackerEntry
- .createEntry(cursor));
- v.setText(rowText);
- }
- }
-}
+/*
+ * Copyright (C) 2008 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.locationtracker.data;
+
+import android.app.ListActivity;
+import android.content.Context;
+import android.database.Cursor;
+import android.view.View;
+import android.widget.ResourceCursorAdapter;
+import android.widget.TextView;
+
+import com.android.locationtracker.R;
+
+/**
+ * Used to bind Tracker data to a list view UI
+ */
+public class TrackerListHelper extends TrackerDataHelper {
+
+ private ListActivity mActivity;
+
+ // sort entries by most recent first
+ private static final String SORT_ORDER = TrackerEntry.ID_COL + " DESC";
+
+ public TrackerListHelper(ListActivity activity) {
+ super(activity, TrackerDataHelper.CSV_FORMATTER);
+ mActivity = activity;
+ }
+
+ /**
+ * Helper method for binding the list activities UI to the tracker data
+ * Tracker data will be sorted in most-recent first order
+ * Will enable automatic UI changes as tracker data changes
+ *
+ * @param layout - layout to populate data
+ */
+ public void bindListUI(int layout) {
+ Cursor cursor = mActivity.managedQuery(TrackerProvider.CONTENT_URI,
+ TrackerEntry.ATTRIBUTES, null, null, SORT_ORDER);
+ // Used to map tracker entries from the database to views
+ TrackerAdapter adapter = new TrackerAdapter(mActivity, layout, cursor);
+ mActivity.setListAdapter(adapter);
+ cursor.setNotificationUri(mActivity.getContentResolver(),
+ TrackerProvider.CONTENT_URI);
+
+ }
+
+ private class TrackerAdapter extends ResourceCursorAdapter {
+
+ public TrackerAdapter(Context context, int layout, Cursor c) {
+ super(context, layout, c);
+ }
+
+ @Override
+ public void bindView(View view, Context context, Cursor cursor) {
+ final TextView v = (TextView) view
+ .findViewById(R.id.entrylist_item);
+ String rowText = mFormatter.getOutput(TrackerEntry
+ .createEntry(cursor));
+ v.setText(rowText);
+ }
+ }
+}
diff --git a/tests/SoundTriggerTestApp/AndroidManifest.xml b/tests/SoundTriggerTestApp/AndroidManifest.xml
index dc4cdb5..71d6001 100644
--- a/tests/SoundTriggerTestApp/AndroidManifest.xml
+++ b/tests/SoundTriggerTestApp/AndroidManifest.xml
@@ -2,7 +2,7 @@
package="com.android.test.soundtrigger">
<uses-permission android:name="android.permission.MANAGE_SOUND_TRIGGER" />
- <uses-permission android:name="android.permission.WAKE_LOCk" />
+ <uses-permission android:name="android.permission.WAKE_LOCK" />
<application>
<activity
android:name="TestSoundTriggerActivity"
diff --git a/tests/SoundTriggerTests/src/android/hardware/soundtrigger/stubhal/GenericSoundModelTest.java b/tests/SoundTriggerTests/src/android/hardware/soundtrigger/stubhal/GenericSoundModelTest.java
index ad02d2b..c0583ce 100644
--- a/tests/SoundTriggerTests/src/android/hardware/soundtrigger/stubhal/GenericSoundModelTest.java
+++ b/tests/SoundTriggerTests/src/android/hardware/soundtrigger/stubhal/GenericSoundModelTest.java
@@ -18,6 +18,7 @@
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.timeout;
import static org.mockito.Mockito.verify;
@@ -40,6 +41,7 @@
import java.net.InetAddress;
import java.net.Socket;
import java.util.ArrayList;
+import java.util.HashSet;
import java.util.Random;
import java.util.UUID;
@@ -53,7 +55,7 @@
static final int MSG_GENERIC_TRIGGER = 4;
private Random random = new Random();
- private ArrayList<UUID> loadedModelUuids;
+ private HashSet<UUID> loadedModelUuids;
private ISoundTriggerService soundTriggerService;
private SoundTriggerManager soundTriggerManager;
@@ -68,7 +70,7 @@
soundTriggerManager = (SoundTriggerManager) context.getSystemService(
Context.SOUND_TRIGGER_SERVICE);
- loadedModelUuids = new ArrayList<UUID>();
+ loadedModelUuids = new HashSet<UUID>();
}
@Override
@@ -170,6 +172,101 @@
verify(spyCallback, timeout(100)).onGenericSoundTriggerDetected(any());
}
+ /**
+ * Tests a more complicated pattern of loading, unloading, triggering, starting and stopping
+ * recognition. Intended to find unexpected errors that occur in unexpected states.
+ */
+ @LargeTest
+ public void testFuzzGenericSoundModel() throws Exception {
+ int numModels = 2;
+
+ final int STATUS_UNLOADED = 0;
+ final int STATUS_LOADED = 1;
+ final int STATUS_STARTED = 2;
+
+ class ModelInfo {
+ int status;
+ GenericSoundModel model;
+
+ public ModelInfo(GenericSoundModel model, int status) {
+ this.status = status;
+ this.model = model;
+ }
+ }
+
+ Random predictableRandom = new Random(100);
+
+ ArrayList modelInfos = new ArrayList<ModelInfo>();
+ for(int i=0; i<numModels; i++) {
+ // Create sound model
+ byte[] data = new byte[1024];
+ predictableRandom.nextBytes(data);
+ UUID modelUuid = UUID.randomUUID();
+ UUID mVendorUuid = UUID.randomUUID();
+ GenericSoundModel model = new GenericSoundModel(modelUuid, mVendorUuid, data);
+ ModelInfo modelInfo = new ModelInfo(model, STATUS_UNLOADED);
+ modelInfos.add(modelInfo);
+ }
+
+ boolean captureTriggerAudio = true;
+ boolean allowMultipleTriggers = true;
+ RecognitionConfig config = new RecognitionConfig(captureTriggerAudio, allowMultipleTriggers,
+ null, null);
+ TestRecognitionStatusCallback spyCallback = spy(new TestRecognitionStatusCallback());
+
+
+ int numOperationsToRun = 100;
+ for(int i=0; i<numOperationsToRun; i++) {
+ // Select a random model
+ int modelInfoIndex = predictableRandom.nextInt(modelInfos.size());
+ ModelInfo modelInfo = (ModelInfo) modelInfos.get(modelInfoIndex);
+
+ // Perform a random operation
+ int operation = predictableRandom.nextInt(5);
+
+ if (operation == 0 && modelInfo.status == STATUS_UNLOADED) {
+ // Update and start sound model
+ soundTriggerService.updateSoundModel(modelInfo.model);
+ loadedModelUuids.add(modelInfo.model.uuid);
+ modelInfo.status = STATUS_LOADED;
+ } else if (operation == 1 && modelInfo.status == STATUS_LOADED) {
+ // Start the sound model
+ int r = soundTriggerService.startRecognition(new ParcelUuid(modelInfo.model.uuid),
+ spyCallback, config);
+ assertEquals("Could Not Start Recognition with code: " + r,
+ android.hardware.soundtrigger.SoundTrigger.STATUS_OK, r);
+ modelInfo.status = STATUS_STARTED;
+ } else if (operation == 2 && modelInfo.status == STATUS_STARTED) {
+ // Send trigger to stub HAL
+ Socket socket = new Socket(InetAddress.getLocalHost(), 14035);
+ DataOutputStream out = new DataOutputStream(socket.getOutputStream());
+ out.writeBytes("trig " + modelInfo.model.uuid + "\r\n");
+ out.flush();
+ socket.close();
+
+ // Verify trigger was received
+ verify(spyCallback, timeout(100)).onGenericSoundTriggerDetected(any());
+ reset(spyCallback);
+ } else if (operation == 3 && modelInfo.status == STATUS_STARTED) {
+ // Stop recognition
+ int r = soundTriggerService.stopRecognition(new ParcelUuid(modelInfo.model.uuid),
+ spyCallback);
+ assertEquals("Could Not Stop Recognition with code: " + r,
+ android.hardware.soundtrigger.SoundTrigger.STATUS_OK, r);
+ modelInfo.status = STATUS_LOADED;
+ } else if (operation == 4 && modelInfo.status != STATUS_UNLOADED) {
+ // Delete sound model
+ soundTriggerService.deleteSoundModel(new ParcelUuid(modelInfo.model.uuid));
+ loadedModelUuids.remove(modelInfo.model.uuid);
+
+ // Confirm it was deleted
+ GenericSoundModel returnedModel =
+ soundTriggerService.getSoundModel(new ParcelUuid(modelInfo.model.uuid));
+ assertEquals(null, returnedModel);
+ modelInfo.status = STATUS_UNLOADED;
+ }
+ }
+ }
public class TestRecognitionStatusCallback extends IRecognitionStatusCallback.Stub {
@Override
diff --git a/tests/VectorDrawableTest/Android.mk b/tests/VectorDrawableTest/Android.mk
index 3d44e33..dd8a4d4 100644
--- a/tests/VectorDrawableTest/Android.mk
+++ b/tests/VectorDrawableTest/Android.mk
@@ -23,6 +23,4 @@
LOCAL_MODULE_TAGS := tests
-LOCAL_SDK_VERSION := current
-
include $(BUILD_PACKAGE)
diff --git a/tests/VectorDrawableTest/AndroidManifest.xml b/tests/VectorDrawableTest/AndroidManifest.xml
index e648897..7b3beb2 100644
--- a/tests/VectorDrawableTest/AndroidManifest.xml
+++ b/tests/VectorDrawableTest/AndroidManifest.xml
@@ -18,8 +18,6 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.test.dynamic" >
- <uses-sdk android:minSdkVersion="21" />
-
<application
android:hardwareAccelerated="true"
android:label="vector"
diff --git a/tests/VectorDrawableTest/res/drawable/btn_radio_on_to_off_bundle.xml b/tests/VectorDrawableTest/res/drawable/btn_radio_on_to_off_bundle.xml
new file mode 100644
index 0000000..4f05090
--- /dev/null
+++ b/tests/VectorDrawableTest/res/drawable/btn_radio_on_to_off_bundle.xml
@@ -0,0 +1,190 @@
+<?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.
+-->
+<animated-vector xmlns:aapt="http://schemas.android.com/aapt"
+ xmlns:android="http://schemas.android.com/apk/res/android">
+ <aapt:attr name="android:drawable">
+ <vector
+ android:width="32dp"
+ android:viewportWidth="32"
+ android:height="32dp"
+ android:viewportHeight="32">
+ <group
+ android:name="btn_radio_to_off_mtrl_0"
+ android:translateX="16"
+ android:translateY="16">
+ <group
+ android:name="ring_outer">
+ <path
+ android:name="ring_outer_path"
+ android:strokeColor="#FF000000"
+ android:strokeWidth="2"
+ android:pathData="M 0.0,-9.0 c 4.9705627482,0.0 9.0,4.0294372518 9.0,9.0 c 0.0,4.9705627482 -4.0294372518,9.0 -9.0,9.0 c -4.9705627482,0.0 -9.0,-4.0294372518 -9.0,-9.0 c 0.0,-4.9705627482 4.0294372518,-9.0 9.0,-9.0 Z"/>
+ </group>
+ <group
+ android:name="dot_group">
+ <path
+ android:name="dot_path"
+ android:pathData="M 0.0,-5.0 c -2.7619934082,0.0 -5.0,2.2380065918 -5.0,5.0 c 0.0,2.7619934082 2.2380065918,5.0 5.0,5.0 c 2.7619934082,0.0 5.0,-2.2380065918 5.0,-5.0 c 0.0,-2.7619934082 -2.2380065918,-5.0 -5.0,-5.0 Z"
+ android:fillColor="#FF000000"/>
+ </group>
+ </group>
+ </vector>
+ </aapt:attr>
+ <target android:name="ring_outer">
+ <aapt:attr name="android:animation">
+ <set
+ xmlns:android="http://schemas.android.com/apk/res/android" >
+ <set
+ android:ordering="sequentially" >
+ <objectAnimator
+ android:duration="183"
+ android:propertyName="scaleX"
+ android:valueFrom="1.0"
+ android:valueTo="0.9"
+ android:valueType="floatType"
+ android:interpolator="@android:interpolator/fast_out_slow_in" />
+ <objectAnimator
+ android:duration="16"
+ android:propertyName="scaleX"
+ android:valueFrom="0.9"
+ android:valueTo="0.5"
+ android:valueType="floatType"
+ android:interpolator="@interpolator/btn_radio_to_off_mtrl_animation_interpolator_0" />
+ <objectAnimator
+ android:duration="300"
+ android:propertyName="scaleX"
+ android:valueFrom="0.5"
+ android:valueTo="1.0"
+ android:valueType="floatType"
+ android:interpolator="@interpolator/btn_radio_to_off_mtrl_animation_interpolator_0" />
+ </set>
+ <set
+ android:ordering="sequentially" >
+ <objectAnimator
+ android:duration="183"
+ android:propertyName="scaleY"
+ android:valueFrom="1.0"
+ android:valueTo="0.9"
+ android:valueType="floatType"
+ android:interpolator="@android:interpolator/fast_out_slow_in" />
+ <objectAnimator
+ android:duration="16"
+ android:propertyName="scaleY"
+ android:valueFrom="0.9"
+ android:valueTo="0.5"
+ android:valueType="floatType"
+ android:interpolator="@interpolator/btn_radio_to_off_mtrl_animation_interpolator_0" />
+ <objectAnimator
+ android:duration="300"
+ android:propertyName="scaleY"
+ android:valueFrom="0.5"
+ android:valueTo="1.0"
+ android:valueType="floatType"
+ android:interpolator="@interpolator/btn_radio_to_off_mtrl_animation_interpolator_0" />
+ </set>
+ </set>
+ </aapt:attr>
+ </target>
+
+ <target android:name="ring_outer_path">
+ <aapt:attr name="android:animation">
+ <set
+ xmlns:android="http://schemas.android.com/apk/res/android">
+ <set
+ android:ordering="sequentially">
+ <objectAnimator
+ android:duration="183"
+ android:propertyName="strokeWidth"
+ android:valueFrom="2.0"
+ android:valueTo="2.0"
+ android:valueType="floatType"
+ android:interpolator="@android:interpolator/fast_out_slow_in"/>
+ <objectAnimator
+ android:duration="16"
+ android:propertyName="strokeWidth"
+ android:valueFrom="2.0"
+ android:valueTo="18.0"
+ android:valueType="floatType"
+ android:interpolator="@android:interpolator/fast_out_slow_in"/>
+ <objectAnimator
+ android:duration="300"
+ android:propertyName="strokeWidth"
+ android:valueFrom="18.0"
+ android:valueTo="2.0"
+ android:valueType="floatType"
+ android:interpolator="@android:interpolator/fast_out_slow_in"/>
+ </set>
+
+ </set>
+ </aapt:attr>
+ </target>
+ <target
+ android:name="dot_group">
+ <aapt:attr name="android:animation">
+ <set
+ xmlns:android="http://schemas.android.com/apk/res/android">
+ <set
+ android:ordering="sequentially">
+ <objectAnimator
+ android:duration="183"
+ android:propertyName="scaleX"
+ android:valueFrom="1.0"
+ android:valueTo="1.4"
+ android:valueType="floatType"
+ android:interpolator="@android:interpolator/fast_out_slow_in"/>
+ <objectAnimator
+ android:duration="16"
+ android:propertyName="scaleX"
+ android:valueFrom="1.4"
+ android:valueTo="0.0"
+ android:valueType="floatType"
+ android:interpolator="@android:interpolator/fast_out_slow_in"/>
+ <objectAnimator
+ android:duration="300"
+ android:propertyName="scaleX"
+ android:valueFrom="0.0"
+ android:valueTo="0.0"
+ android:valueType="floatType"
+ android:interpolator="@android:interpolator/fast_out_slow_in"/>
+ </set>
+ <set
+ android:ordering="sequentially">
+ <objectAnimator
+ android:duration="183"
+ android:propertyName="scaleY"
+ android:valueFrom="1.0"
+ android:valueTo="1.4"
+ android:valueType="floatType"
+ android:interpolator="@android:interpolator/fast_out_slow_in"/>
+ <objectAnimator
+ android:duration="16"
+ android:propertyName="scaleY"
+ android:valueFrom="1.4"
+ android:valueTo="0.0"
+ android:valueType="floatType"
+ android:interpolator="@android:interpolator/fast_out_slow_in"/>
+ <objectAnimator
+ android:duration="300"
+ android:propertyName="scaleY"
+ android:valueFrom="0.0"
+ android:valueTo="0.0"
+ android:valueType="floatType"
+ android:interpolator="@android:interpolator/fast_out_slow_in"/>
+ </set>
+ </set>
+ </aapt:attr>
+ </target>
+</animated-vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable_linear_progress_bar.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable_linear_progress_bar.xml
index 96fd70e..a6da114 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_drawable_linear_progress_bar.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable_linear_progress_bar.xml
@@ -17,7 +17,7 @@
android:height="4dp"
android:viewportHeight="4"
android:viewportWidth="360"
- android:width="360dp" >
+ android:width="36dp" >
<group
android:name="linear_indeterminate"
diff --git a/tests/VectorDrawableTest/res/interpolator/btn_radio_to_off_mtrl_animation_interpolator_0.xml b/tests/VectorDrawableTest/res/interpolator/btn_radio_to_off_mtrl_animation_interpolator_0.xml
new file mode 100644
index 0000000..d3728c4
--- /dev/null
+++ b/tests/VectorDrawableTest/res/interpolator/btn_radio_to_off_mtrl_animation_interpolator_0.xml
@@ -0,0 +1,19 @@
+<?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.
+-->
+
+<pathInterpolator
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:pathData="M 0.0,0.0 c 0.4,0.0 0.4,1.0 1.0,1.0" />
diff --git a/tests/VectorDrawableTest/src/com/android/test/dynamic/AnimatedVectorDrawableTest.java b/tests/VectorDrawableTest/src/com/android/test/dynamic/AnimatedVectorDrawableTest.java
index 087e68a..8f538ae 100644
--- a/tests/VectorDrawableTest/src/com/android/test/dynamic/AnimatedVectorDrawableTest.java
+++ b/tests/VectorDrawableTest/src/com/android/test/dynamic/AnimatedVectorDrawableTest.java
@@ -24,11 +24,13 @@
import android.widget.Button;
import android.widget.GridLayout;
import android.widget.ScrollView;
+import android.widget.TextView;
public class AnimatedVectorDrawableTest extends Activity implements View.OnClickListener {
private static final String LOGCAT = "AnimatedVectorDrawableTest";
protected int[] icon = {
+ R.drawable.btn_radio_on_to_off_bundle,
R.drawable.ic_rotate_2_portrait_v2_animation,
R.drawable.ic_signal_airplane_v2_animation,
R.drawable.ic_hourglass_animation,
@@ -43,33 +45,53 @@
@Override
protected void onCreate(Bundle savedInstanceState) {
+ final int[] layerTypes = {View.LAYER_TYPE_SOFTWARE, View.LAYER_TYPE_HARDWARE};
+ final boolean[] forceOnUi = {false, true};
super.onCreate(savedInstanceState);
ScrollView scrollView = new ScrollView(this);
GridLayout container = new GridLayout(this);
scrollView.addView(container);
- container.setColumnCount(1);
+ container.setColumnCount(layerTypes.length * forceOnUi.length);
+ for (int j = 0; j < layerTypes.length; j++) {
+ for (int k = 0; k < forceOnUi.length; k++) {
+ TextView textView = new TextView(this);
+ String category = "Layer:"
+ + (layerTypes[j] == View.LAYER_TYPE_SOFTWARE ? "SW" : "HW")
+ + (forceOnUi[k] == true ? ",forceUI" : "");
+ textView.setText(category);
+ container.addView(textView);
+ }
+ }
for (int i = 0; i < icon.length; i++) {
- Button button = new Button(this);
- button.setWidth(400);
- button.setHeight(400);
- button.setBackgroundResource(icon[i]);
- AnimatedVectorDrawable d = (AnimatedVectorDrawable) button.getBackground();
- d.registerAnimationCallback(new Animatable2.AnimationCallback() {
- @Override
- public void onAnimationStart(Drawable drawable) {
- Log.v(LOGCAT, "Animator start");
- }
+ for (int j = 0; j < layerTypes.length; j++) {
+ for (int k = 0; k < forceOnUi.length; k++) {
+ Button button = new Button(this);
+ button.setWidth(300);
+ button.setHeight(300);
+ button.setLayerType(layerTypes[j], null);
+ button.setBackgroundResource(icon[i]);
+ AnimatedVectorDrawable d = (AnimatedVectorDrawable) button.getBackground();
+ if (forceOnUi[k] == true) {
+ d.forceAnimationOnUI();
+ }
+ d.registerAnimationCallback(new Animatable2.AnimationCallback() {
+ @Override
+ public void onAnimationStart(Drawable drawable) {
+ Log.v(LOGCAT, "Animator start");
+ }
- @Override
- public void onAnimationEnd(Drawable drawable) {
- Log.v(LOGCAT, "Animator end");
- }
- });
+ @Override
+ public void onAnimationEnd(Drawable drawable) {
+ Log.v(LOGCAT, "Animator end");
+ }
+ });
- container.addView(button);
- button.setOnClickListener(this);
+ container.addView(button);
+ button.setOnClickListener(this);
+ }
+ }
}
setContentView(scrollView);
diff --git a/tools/aapt/AaptAssets.cpp b/tools/aapt/AaptAssets.cpp
index cbd8480..c1cfd0b 100644
--- a/tools/aapt/AaptAssets.cpp
+++ b/tools/aapt/AaptAssets.cpp
@@ -388,10 +388,6 @@
if (script[0]) {
memcpy(out->localeScript, script, sizeof(out->localeScript));
- out->localeScriptWasComputed = false;
- } else {
- out->computeScript();
- out->localeScriptWasComputed = true;
}
if (variant[0]) {
diff --git a/tools/aapt/Package.cpp b/tools/aapt/Package.cpp
index 641c34b..d631f35 100644
--- a/tools/aapt/Package.cpp
+++ b/tools/aapt/Package.cpp
@@ -33,7 +33,7 @@
".mpg", ".mpeg", ".mid", ".midi", ".smf", ".jet",
".rtttl", ".imy", ".xmf", ".mp4", ".m4a",
".m4v", ".3gp", ".3gpp", ".3g2", ".3gpp2",
- ".amr", ".awb", ".wma", ".wmv", ".webm"
+ ".amr", ".awb", ".wma", ".wmv", ".webm", ".mkv"
};
/* fwd decls, so I can write this downward */
diff --git a/tools/aapt2/Android.mk b/tools/aapt2/Android.mk
index 85d22ff..876a422 100644
--- a/tools/aapt2/Android.mk
+++ b/tools/aapt2/Android.mk
@@ -54,6 +54,7 @@
Debug.cpp \
Flags.cpp \
java/AnnotationProcessor.cpp \
+ java/ClassDefinition.cpp \
java/JavaClassGenerator.cpp \
java/ManifestClassGenerator.cpp \
java/ProguardRules.cpp \
diff --git a/tools/aapt2/Locale.cpp b/tools/aapt2/Locale.cpp
index 12f56fc..be57661 100644
--- a/tools/aapt2/Locale.cpp
+++ b/tools/aapt2/Locale.cpp
@@ -268,10 +268,6 @@
if (script[0]) {
memcpy(out->localeScript, script, sizeof(out->localeScript));
- out->localeScriptWasComputed = false;
- } else {
- out->computeScript();
- out->localeScriptWasComputed = true;
}
if (variant[0]) {
diff --git a/tools/aapt2/integration-tests/StaticLibOne/Android.mk b/tools/aapt2/integration-tests/StaticLibOne/Android.mk
index d59dc60..0b7129a 100644
--- a/tools/aapt2/integration-tests/StaticLibOne/Android.mk
+++ b/tools/aapt2/integration-tests/StaticLibOne/Android.mk
@@ -22,4 +22,7 @@
LOCAL_MODULE_TAGS := tests
LOCAL_SRC_FILES := $(call all-java-files-under,src)
LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
+
+# We need this to compile the Java sources of AaptTestStaticLibTwo using javac.
+LOCAL_JAR_EXCLUDE_FILES := none
include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/tools/aapt2/java/AnnotationProcessor.cpp b/tools/aapt2/java/AnnotationProcessor.cpp
index 496e92e..ba74439 100644
--- a/tools/aapt2/java/AnnotationProcessor.cpp
+++ b/tools/aapt2/java/AnnotationProcessor.cpp
@@ -64,7 +64,7 @@
mComment << "\n *";
}
-void AnnotationProcessor::writeToStream(std::ostream* out, const StringPiece& prefix) {
+void AnnotationProcessor::writeToStream(std::ostream* out, const StringPiece& prefix) const {
if (mHasComments) {
std::string result = mComment.str();
for (StringPiece line : util::tokenize<char>(result, '\n')) {
diff --git a/tools/aapt2/java/AnnotationProcessor.h b/tools/aapt2/java/AnnotationProcessor.h
index fadf584..0fc5b08 100644
--- a/tools/aapt2/java/AnnotationProcessor.h
+++ b/tools/aapt2/java/AnnotationProcessor.h
@@ -66,7 +66,7 @@
/**
* Writes the comments and annotations to the stream, with the given prefix before each line.
*/
- void writeToStream(std::ostream* out, const StringPiece& prefix);
+ void writeToStream(std::ostream* out, const StringPiece& prefix) const;
private:
enum : uint32_t {
diff --git a/tools/aapt2/java/ClassDefinition.cpp b/tools/aapt2/java/ClassDefinition.cpp
new file mode 100644
index 0000000..08f2c8b
--- /dev/null
+++ b/tools/aapt2/java/ClassDefinition.cpp
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "java/ClassDefinition.h"
+#include "util/StringPiece.h"
+
+#include <ostream>
+
+namespace aapt {
+
+bool ClassDefinition::empty() const {
+ for (const std::unique_ptr<ClassMember>& member : mMembers) {
+ if (!member->empty()) {
+ return false;
+ }
+ }
+ return true;
+}
+
+void ClassDefinition::writeToStream(const StringPiece& prefix, bool final,
+ std::ostream* out) const {
+ if (mMembers.empty() && !mCreateIfEmpty) {
+ return;
+ }
+
+ ClassMember::writeToStream(prefix, final, out);
+
+ *out << prefix << "public ";
+ if (mQualifier == ClassQualifier::Static) {
+ *out << "static ";
+ }
+ *out << "final class " << mName << " {\n";
+
+ std::string newPrefix = prefix.toString();
+ newPrefix.append(kIndent);
+
+ for (const std::unique_ptr<ClassMember>& member : mMembers) {
+ member->writeToStream(newPrefix, final, out);
+ *out << "\n";
+ }
+
+ *out << prefix << "}";
+}
+
+constexpr static const char* sWarningHeader =
+ "/* AUTO-GENERATED FILE. DO NOT MODIFY.\n"
+ " *\n"
+ " * This class was automatically generated by the\n"
+ " * aapt tool from the resource data it found. It\n"
+ " * should not be modified by hand.\n"
+ " */\n\n";
+
+bool ClassDefinition::writeJavaFile(const ClassDefinition* def,
+ const StringPiece& package,
+ bool final,
+ std::ostream* out) {
+ *out << sWarningHeader << "package " << package << ";\n\n";
+ def->writeToStream("", final, out);
+ return bool(*out);
+}
+
+} // namespace aapt
diff --git a/tools/aapt2/java/ClassDefinition.h b/tools/aapt2/java/ClassDefinition.h
new file mode 100644
index 0000000..53e0f6f
--- /dev/null
+++ b/tools/aapt2/java/ClassDefinition.h
@@ -0,0 +1,188 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef AAPT_JAVA_CLASSDEFINITION_H
+#define AAPT_JAVA_CLASSDEFINITION_H
+
+#include "Resource.h"
+#include "java/AnnotationProcessor.h"
+#include "util/StringPiece.h"
+#include "util/Util.h"
+
+#include <android-base/macros.h>
+#include <sstream>
+#include <string>
+
+namespace aapt {
+
+// The number of attributes to emit per line in a Styleable array.
+constexpr static size_t kAttribsPerLine = 4;
+constexpr static const char* kIndent = " ";
+
+class ClassMember {
+public:
+ virtual ~ClassMember() = default;
+
+ AnnotationProcessor* getCommentBuilder() {
+ return &mProcessor;
+ }
+
+ virtual bool empty() const = 0;
+
+ virtual void writeToStream(const StringPiece& prefix, bool final, std::ostream* out) const {
+ mProcessor.writeToStream(out, prefix);
+ }
+
+private:
+ AnnotationProcessor mProcessor;
+};
+
+template <typename T>
+class PrimitiveMember : public ClassMember {
+public:
+ PrimitiveMember(const StringPiece& name, const T& val) :
+ mName(name.toString()), mVal(val) {
+ }
+
+ bool empty() const override {
+ return false;
+ }
+
+ void writeToStream(const StringPiece& prefix, bool final, std::ostream* out) const override {
+ ClassMember::writeToStream(prefix, final, out);
+
+ *out << prefix << "public static " << (final ? "final " : "")
+ << "int " << mName << "=" << mVal << ";";
+ }
+
+private:
+ std::string mName;
+ T mVal;
+
+ DISALLOW_COPY_AND_ASSIGN(PrimitiveMember);
+};
+
+/**
+ * Specialization for strings so they get the right type and are quoted with "".
+ */
+template <>
+class PrimitiveMember<std::string> : public ClassMember {
+public:
+ PrimitiveMember(const StringPiece& name, const std::string& val) :
+ mName(name.toString()), mVal(val) {
+ }
+
+ bool empty() const override {
+ return false;
+ }
+
+ void writeToStream(const StringPiece& prefix, bool final, std::ostream* out) const override {
+ ClassMember::writeToStream(prefix, final, out);
+
+ *out << prefix << "public static " << (final ? "final " : "")
+ << "String " << mName << "=\"" << mVal << "\";";
+ }
+
+private:
+ std::string mName;
+ std::string mVal;
+
+ DISALLOW_COPY_AND_ASSIGN(PrimitiveMember);
+};
+
+using IntMember = PrimitiveMember<uint32_t>;
+using ResourceMember = PrimitiveMember<ResourceId>;
+using StringMember = PrimitiveMember<std::string>;
+
+template <typename T>
+class PrimitiveArrayMember : public ClassMember {
+public:
+ PrimitiveArrayMember(const StringPiece& name) :
+ mName(name.toString()) {
+ }
+
+ void addElement(const T& val) {
+ mElements.push_back(val);
+ }
+
+ bool empty() const override {
+ return false;
+ }
+
+ void writeToStream(const StringPiece& prefix, bool final, std::ostream* out) const override {
+ ClassMember::writeToStream(prefix, final, out);
+
+ *out << "public static final int[] " << mName << "={";
+
+ const auto begin = mElements.begin();
+ const auto end = mElements.end();
+ for (auto current = begin; current != end; ++current) {
+ if (std::distance(begin, current) % kAttribsPerLine == 0) {
+ *out << "\n" << prefix << kIndent << kIndent;
+ }
+
+ *out << *current;
+ if (std::distance(current, end) > 1) {
+ *out << ", ";
+ }
+ }
+ *out << "\n" << prefix << kIndent <<"};";
+ }
+
+private:
+ std::string mName;
+ std::vector<T> mElements;
+
+ DISALLOW_COPY_AND_ASSIGN(PrimitiveArrayMember);
+};
+
+using ResourceArrayMember = PrimitiveArrayMember<ResourceId>;
+
+enum class ClassQualifier {
+ None,
+ Static
+};
+
+class ClassDefinition : public ClassMember {
+public:
+ static bool writeJavaFile(const ClassDefinition* def,
+ const StringPiece& package,
+ bool final,
+ std::ostream* out);
+
+ ClassDefinition(const StringPiece& name, ClassQualifier qualifier, bool createIfEmpty) :
+ mName(name.toString()), mQualifier(qualifier), mCreateIfEmpty(createIfEmpty) {
+ }
+
+ void addMember(std::unique_ptr<ClassMember> member) {
+ mMembers.push_back(std::move(member));
+ }
+
+ bool empty() const override;
+ void writeToStream(const StringPiece& prefix, bool final, std::ostream* out) const override;
+
+private:
+ std::string mName;
+ ClassQualifier mQualifier;
+ bool mCreateIfEmpty;
+ std::vector<std::unique_ptr<ClassMember>> mMembers;
+
+ DISALLOW_COPY_AND_ASSIGN(ClassDefinition);
+};
+
+} // namespace aapt
+
+#endif /* AAPT_JAVA_CLASSDEFINITION_H */
diff --git a/tools/aapt2/java/ClassDefinitionWriter.h b/tools/aapt2/java/ClassDefinitionWriter.h
deleted file mode 100644
index cf92c9a..0000000
--- a/tools/aapt2/java/ClassDefinitionWriter.h
+++ /dev/null
@@ -1,142 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef AAPT_JAVA_CLASSDEFINITION_H
-#define AAPT_JAVA_CLASSDEFINITION_H
-
-#include "Resource.h"
-#include "java/AnnotationProcessor.h"
-#include "util/StringPiece.h"
-#include "util/Util.h"
-
-#include <sstream>
-#include <string>
-
-namespace aapt {
-
-struct ClassDefinitionWriterOptions {
- bool useFinalQualifier = false;
- bool forceCreationIfEmpty = false;
-};
-
-/**
- * Writes a class for use in R.java or Manifest.java.
- */
-class ClassDefinitionWriter {
-public:
- ClassDefinitionWriter(const StringPiece& name, const ClassDefinitionWriterOptions& options) :
- mName(name.toString()), mOptions(options), mStarted(false) {
- }
-
- ClassDefinitionWriter(const StringPiece16& name, const ClassDefinitionWriterOptions& options) :
- mName(util::utf16ToUtf8(name)), mOptions(options), mStarted(false) {
- }
-
- void addIntMember(const StringPiece& name, AnnotationProcessor* processor,
- const uint32_t val) {
- ensureClassDeclaration();
- if (processor) {
- processor->writeToStream(&mOut, kIndent);
- }
- mOut << kIndent << "public static " << (mOptions.useFinalQualifier ? "final " : "")
- << "int " << name << "=" << val << ";\n";
- }
-
- void addStringMember(const StringPiece16& name, AnnotationProcessor* processor,
- const StringPiece16& val) {
- ensureClassDeclaration();
- if (processor) {
- processor->writeToStream(&mOut, kIndent);
- }
- mOut << kIndent << "public static " << (mOptions.useFinalQualifier ? "final " : "")
- << "String " << name << "=\"" << val << "\";\n";
- }
-
- void addResourceMember(const StringPiece& name, AnnotationProcessor* processor,
- const ResourceId id) {
- ensureClassDeclaration();
- if (processor) {
- processor->writeToStream(&mOut, kIndent);
- }
- mOut << kIndent << "public static " << (mOptions.useFinalQualifier ? "final " : "")
- << "int " << name << "=" << id <<";\n";
- }
-
- template <typename Iterator, typename FieldAccessorFunc>
- void addArrayMember(const StringPiece& name, AnnotationProcessor* processor,
- const Iterator begin, const Iterator end, FieldAccessorFunc f) {
- ensureClassDeclaration();
- if (processor) {
- processor->writeToStream(&mOut, kIndent);
- }
- mOut << kIndent << "public static final int[] " << name << "={";
-
- for (Iterator current = begin; current != end; ++current) {
- if (std::distance(begin, current) % kAttribsPerLine == 0) {
- mOut << "\n" << kIndent << kIndent;
- }
-
- mOut << f(*current);
- if (std::distance(current, end) > 1) {
- mOut << ", ";
- }
- }
- mOut << "\n" << kIndent <<"};\n";
- }
-
- void writeToStream(std::ostream* out, const StringPiece& prefix,
- AnnotationProcessor* processor=nullptr) {
- if (mOptions.forceCreationIfEmpty) {
- ensureClassDeclaration();
- }
-
- if (!mStarted) {
- return;
- }
-
- if (processor) {
- processor->writeToStream(out, prefix);
- }
-
- std::string result = mOut.str();
- for (StringPiece line : util::tokenize<char>(result, '\n')) {
- *out << prefix << line << "\n";
- }
- *out << prefix << "}\n";
- }
-
-private:
- constexpr static const char* kIndent = " ";
-
- // The number of attributes to emit per line in a Styleable array.
- constexpr static size_t kAttribsPerLine = 4;
-
- void ensureClassDeclaration() {
- if (!mStarted) {
- mStarted = true;
- mOut << "public static final class " << mName << " {\n";
- }
- }
-
- std::stringstream mOut;
- std::string mName;
- ClassDefinitionWriterOptions mOptions;
- bool mStarted;
-};
-
-} // namespace aapt
-
-#endif /* AAPT_JAVA_CLASSDEFINITION_H */
diff --git a/tools/aapt2/java/JavaClassGenerator.cpp b/tools/aapt2/java/JavaClassGenerator.cpp
index 01330dc..092bab24 100644
--- a/tools/aapt2/java/JavaClassGenerator.cpp
+++ b/tools/aapt2/java/JavaClassGenerator.cpp
@@ -21,7 +21,7 @@
#include "ValueVisitor.h"
#include "java/AnnotationProcessor.h"
-#include "java/ClassDefinitionWriter.h"
+#include "java/ClassDefinition.h"
#include "java/JavaClassGenerator.h"
#include "process/SymbolTable.h"
#include "util/StringPiece.h"
@@ -39,16 +39,6 @@
mContext(context), mTable(table), mOptions(options) {
}
-static void generateHeader(const StringPiece16& packageNameToGenerate, std::ostream* out) {
- *out << "/* AUTO-GENERATED FILE. DO NOT MODIFY.\n"
- " *\n"
- " * This class was automatically generated by the\n"
- " * aapt tool from the resource data it found. It\n"
- " * should not be modified by hand.\n"
- " */\n\n"
- "package " << packageNameToGenerate << ";\n\n";
-}
-
static const std::set<StringPiece16> sJavaIdentifiers = {
u"abstract", u"assert", u"boolean", u"break", u"byte",
u"case", u"catch", u"char", u"class", u"const", u"continue",
@@ -110,15 +100,15 @@
if (typeMask & android::ResTable_map::TYPE_REFERENCE) {
processor->appendComment(
"<p>May be a reference to another resource, in the form\n"
- "\"<code>@[+][<i>package</i>:]<i>type</i>/<i>name</i></code>\" or a theme\n"
- "attribute in the form\n"
- "\"<code>?[<i>package</i>:]<i>type</i>/<i>name</i></code>\".");
+ "\"<code>@[+][<i>package</i>:]<i>type</i>/<i>name</i></code>\" or a theme\n"
+ "attribute in the form\n"
+ "\"<code>?[<i>package</i>:]<i>type</i>/<i>name</i></code>\".");
}
if (typeMask & android::ResTable_map::TYPE_STRING) {
processor->appendComment(
"<p>May be a string value, using '\\\\;' to escape characters such as\n"
- "'\\\\n' or '\\\\uxxxx' for a unicode character;");
+ "'\\\\n' or '\\\\uxxxx' for a unicode character;");
}
if (typeMask & android::ResTable_map::TYPE_INTEGER) {
@@ -128,14 +118,14 @@
if (typeMask & android::ResTable_map::TYPE_BOOLEAN) {
processor->appendComment(
"<p>May be a boolean value, such as \"<code>true</code>\" or\n"
- "\"<code>false</code>\".");
+ "\"<code>false</code>\".");
}
if (typeMask & android::ResTable_map::TYPE_COLOR) {
processor->appendComment(
"<p>May be a color value, in the form of \"<code>#<i>rgb</i></code>\",\n"
- "\"<code>#<i>argb</i></code>\", \"<code>#<i>rrggbb</i></code\", or \n"
- "\"<code>#<i>aarrggbb</i></code>\".");
+ "\"<code>#<i>argb</i></code>\", \"<code>#<i>rrggbb</i></code\", or \n"
+ "\"<code>#<i>aarrggbb</i></code>\".");
}
if (typeMask & android::ResTable_map::TYPE_FLOAT) {
@@ -146,33 +136,33 @@
if (typeMask & android::ResTable_map::TYPE_DIMENSION) {
processor->appendComment(
"<p>May be a dimension value, which is a floating point number appended with a\n"
- "unit such as \"<code>14.5sp</code>\".\n"
- "Available units are: px (pixels), dp (density-independent pixels),\n"
- "sp (scaled pixels based on preferred font size), in (inches), and\n"
- "mm (millimeters).");
+ "unit such as \"<code>14.5sp</code>\".\n"
+ "Available units are: px (pixels), dp (density-independent pixels),\n"
+ "sp (scaled pixels based on preferred font size), in (inches), and\n"
+ "mm (millimeters).");
}
if (typeMask & android::ResTable_map::TYPE_FRACTION) {
processor->appendComment(
"<p>May be a fractional value, which is a floating point number appended with\n"
- "either % or %p, such as \"<code>14.5%</code>\".\n"
- "The % suffix always means a percentage of the base size;\n"
- "the optional %p suffix provides a size relative to some parent container.");
+ "either % or %p, such as \"<code>14.5%</code>\".\n"
+ "The % suffix always means a percentage of the base size;\n"
+ "the optional %p suffix provides a size relative to some parent container.");
}
if (typeMask & (android::ResTable_map::TYPE_FLAGS | android::ResTable_map::TYPE_ENUM)) {
if (typeMask & android::ResTable_map::TYPE_FLAGS) {
processor->appendComment(
"<p>Must be one or more (separated by '|') of the following "
- "constant values.</p>");
+ "constant values.</p>");
} else {
processor->appendComment("<p>Must be one of the following constant values.</p>");
}
processor->appendComment("<table>\n<colgroup align=\"left\" />\n"
- "<colgroup align=\"left\" />\n"
- "<colgroup align=\"left\" />\n"
- "<tr><th>Constant</th><th>Value</th><th>Description</th></tr>\n");
+ "<colgroup align=\"left\" />\n"
+ "<colgroup align=\"left\" />\n"
+ "<tr><th>Constant</th><th>Value</th><th>Description</th></tr>\n");
for (const Attribute::Symbol& symbol : attr->symbols) {
std::stringstream line;
line << "<tr><td>" << symbol.symbol.name.value().entry << "</td>"
@@ -214,13 +204,15 @@
}
}
-void JavaClassGenerator::writeStyleableEntryForClass(ClassDefinitionWriter* outClassDef,
- AnnotationProcessor* processor,
- const StringPiece16& packageNameToGenerate,
- const std::u16string& entryName,
- const Styleable* styleable) {
+void JavaClassGenerator::addMembersToStyleableClass(const StringPiece16& packageNameToGenerate,
+ const std::u16string& entryName,
+ const Styleable* styleable,
+ ClassDefinition* outStyleableClassDef) {
const std::string className = transform(entryName);
+ std::unique_ptr<ResourceArrayMember> styleableArrayDef =
+ util::make_unique<ResourceArrayMember>(className);
+
// This must be sorted by resource ID.
std::vector<StyleableAttr> sortedAttributes;
sortedAttributes.reserve(styleable->entries.size());
@@ -230,6 +222,8 @@
assert((!mOptions.useFinal || attr.id) && "no ID set for Styleable entry");
assert(attr.name && "no name set for Styleable entry");
+ // We will need the unmangled, transformed name in the comments and the field,
+ // so create it once and cache it in this StyleableAttr data structure.
StyleableAttr styleableAttr = {};
styleableAttr.attrRef = &attr;
styleableAttr.fieldName = transformNestedAttr(attr.name.value(), className,
@@ -247,6 +241,8 @@
mangledReference.name = mangledName;
}
+ // Look up the symbol so that we can write out in the comments what are possible
+ // legal values for this attribute.
const SymbolTable::Symbol* symbol = mContext->getExternalSymbols()->findByReference(
mangledReference);
if (symbol) {
@@ -254,10 +250,11 @@
}
sortedAttributes.push_back(std::move(styleableAttr));
}
+
+ // Sort the attributes by ID.
std::sort(sortedAttributes.begin(), sortedAttributes.end(), lessStyleableAttr);
const size_t attrCount = sortedAttributes.size();
-
if (attrCount > 0) {
// Build the comment string for the Styleable. It includes details about the
// child attributes.
@@ -267,6 +264,7 @@
} else {
styleableComment << "Attributes that can be used with a " << className << ".\n";
}
+
styleableComment <<
"<p>Includes the following attributes:</p>\n"
"<table>\n"
@@ -274,7 +272,7 @@
"<colgroup align=\"left\" />\n"
"<tr><th>Attribute</th><th>Description</th></tr>\n";
- for (const auto& entry : sortedAttributes) {
+ for (const StyleableAttr& entry : sortedAttributes) {
const ResourceName& attrName = entry.attrRef->name.value();
styleableComment << "<tr><td>";
styleableComment << "<code>{@link #"
@@ -292,21 +290,22 @@
styleableComment << "</td></tr>\n";
}
styleableComment << "</table>\n";
- for (const auto& entry : sortedAttributes) {
+
+ for (const StyleableAttr& entry : sortedAttributes) {
styleableComment << "@see #" << entry.fieldName << "\n";
}
- processor->appendComment(styleableComment.str());
+
+ styleableArrayDef->getCommentBuilder()->appendComment(styleableComment.str());
}
- auto accessorFunc = [](const StyleableAttr& a) -> ResourceId {
- return a.attrRef->id ? a.attrRef->id.value() : ResourceId(0);
- };
+ // Add the ResourceIds to the array member.
+ for (const StyleableAttr& styleableAttr : sortedAttributes) {
+ styleableArrayDef->addElement(
+ styleableAttr.attrRef->id ? styleableAttr.attrRef->id.value() : ResourceId(0));
+ }
- // First we emit the array containing the IDs of each attribute.
- outClassDef->addArrayMember(className, processor,
- sortedAttributes.begin(),
- sortedAttributes.end(),
- accessorFunc);
+ // Add the Styleable array to the Styleable class.
+ outStyleableClassDef->addMember(std::move(styleableArrayDef));
// Now we emit the indices into the array.
for (size_t i = 0; i < attrCount; i++) {
@@ -318,7 +317,10 @@
packageName = mContext->getCompilationPackage();
}
- AnnotationProcessor attrProcessor;
+ std::unique_ptr<IntMember> indexMember = util::make_unique<IntMember>(
+ sortedAttributes[i].fieldName, i);
+
+ AnnotationProcessor* attrProcessor = indexMember->getCommentBuilder();
StringPiece16 comment = styleableAttr.attrRef->getComment();
if (styleableAttr.attribute && comment.empty()) {
@@ -326,8 +328,8 @@
}
if (!comment.empty()) {
- attrProcessor.appendComment("<p>\n@attr description");
- attrProcessor.appendComment(comment);
+ attrProcessor->appendComment("<p>\n@attr description");
+ attrProcessor->appendComment(comment);
} else {
std::stringstream defaultComment;
defaultComment
@@ -335,27 +337,29 @@
<< "{@link " << packageName << ".R.attr#" << transform(attrName.entry) << "}\n"
<< "attribute's value can be found in the "
<< "{@link #" << className << "} array.";
- attrProcessor.appendComment(defaultComment.str());
+ attrProcessor->appendComment(defaultComment.str());
}
- attrProcessor.appendNewLine();
+ attrProcessor->appendNewLine();
if (styleableAttr.attribute) {
- addAttributeFormatDoc(&attrProcessor, styleableAttr.attribute.get());
- attrProcessor.appendNewLine();
+ addAttributeFormatDoc(attrProcessor, styleableAttr.attribute.get());
+ attrProcessor->appendNewLine();
}
std::stringstream doclavaName;
doclavaName << "@attr name " << packageName << ":" << attrName.entry;;
- attrProcessor.appendComment(doclavaName.str());
- outClassDef->addIntMember(sortedAttributes[i].fieldName, &attrProcessor, i);
+ attrProcessor->appendComment(doclavaName.str());
+
+ outStyleableClassDef->addMember(std::move(indexMember));
}
}
-bool JavaClassGenerator::writeEntriesForClass(ClassDefinitionWriter* outClassDef,
- const StringPiece16& packageNameToGenerate,
- const ResourceTablePackage* package,
- const ResourceTableType* type) {
+bool JavaClassGenerator::addMembersToTypeClass(const StringPiece16& packageNameToGenerate,
+ const ResourceTablePackage* package,
+ const ResourceTableType* type,
+ ClassDefinition* outTypeClassDef) {
+
for (const auto& entry : type->entries) {
if (skipSymbol(entry->symbolStatus.state)) {
continue;
@@ -389,33 +393,41 @@
return false;
}
- // Build the comments and annotations for this entry.
-
- AnnotationProcessor processor;
- if (entry->symbolStatus.state != SymbolState::kUndefined) {
- processor.appendComment(entry->symbolStatus.comment);
- }
-
- for (const auto& configValue : entry->values) {
- processor.appendComment(configValue->value->getComment());
- }
-
- // If this is an Attribute, append the format Javadoc.
- if (!entry->values.empty()) {
- if (Attribute* attr = valueCast<Attribute>(entry->values.front()->value.get())) {
- // We list out the available values for the given attribute.
- addAttributeFormatDoc(&processor, attr);
- }
- }
-
if (type->type == ResourceType::kStyleable) {
assert(!entry->values.empty());
+
const Styleable* styleable = static_cast<const Styleable*>(
entry->values.front()->value.get());
- writeStyleableEntryForClass(outClassDef, &processor, packageNameToGenerate,
- unmangledName, styleable);
+
+ // Comments are handled within this method.
+ addMembersToStyleableClass(packageNameToGenerate, unmangledName, styleable,
+ outTypeClassDef);
} else {
- outClassDef->addResourceMember(transform(unmangledName), &processor, id);
+ std::unique_ptr<ResourceMember> resourceMember =
+ util::make_unique<ResourceMember>(transform(unmangledName), id);
+
+ // Build the comments and annotations for this entry.
+ AnnotationProcessor* processor = resourceMember->getCommentBuilder();
+
+ // Add the comments from any <public> tags.
+ if (entry->symbolStatus.state != SymbolState::kUndefined) {
+ processor->appendComment(entry->symbolStatus.comment);
+ }
+
+ // Add the comments from all configurations of this entry.
+ for (const auto& configValue : entry->values) {
+ processor->appendComment(configValue->value->getComment());
+ }
+
+ // If this is an Attribute, append the format Javadoc.
+ if (!entry->values.empty()) {
+ if (Attribute* attr = valueCast<Attribute>(entry->values.front()->value.get())) {
+ // We list out the available values for the given attribute.
+ addAttributeFormatDoc(processor, attr);
+ }
+ }
+
+ outTypeClassDef->addMember(std::move(resourceMember));
}
}
return true;
@@ -425,11 +437,19 @@
return generate(packageNameToGenerate, packageNameToGenerate, out);
}
+static void appendJavaDocAnnotations(const std::vector<std::string>& annotations,
+ AnnotationProcessor* processor) {
+ for (const std::string& annotation : annotations) {
+ std::string properAnnotation = "@";
+ properAnnotation += annotation;
+ processor->appendComment(properAnnotation);
+ }
+}
+
bool JavaClassGenerator::generate(const StringPiece16& packageNameToGenerate,
const StringPiece16& outPackageName, std::ostream* out) {
- generateHeader(outPackageName, out);
- *out << "public final class R {\n";
+ ClassDefinition rClass("R", ClassQualifier::None, true);
for (const auto& package : mTable->packages) {
for (const auto& type : package->types) {
@@ -437,13 +457,15 @@
continue;
}
- ClassDefinitionWriterOptions classOptions;
- classOptions.useFinalQualifier = mOptions.useFinal;
- classOptions.forceCreationIfEmpty =
+ const bool forceCreationIfEmpty =
(mOptions.types == JavaClassGeneratorOptions::SymbolTypes::kPublic);
- ClassDefinitionWriter classDef(toString(type->type), classOptions);
- bool result = writeEntriesForClass(&classDef, packageNameToGenerate,
- package.get(), type.get());
+
+ std::unique_ptr<ClassDefinition> classDef = util::make_unique<ClassDefinition>(
+ util::utf16ToUtf8(toString(type->type)), ClassQualifier::Static,
+ forceCreationIfEmpty);
+
+ bool result = addMembersToTypeClass(packageNameToGenerate, package.get(), type.get(),
+ classDef.get());
if (!result) {
return false;
}
@@ -452,30 +474,36 @@
// Also include private attributes in this same class.
ResourceTableType* privType = package->findType(ResourceType::kAttrPrivate);
if (privType) {
- result = writeEntriesForClass(&classDef, packageNameToGenerate,
- package.get(), privType);
+ result = addMembersToTypeClass(packageNameToGenerate, package.get(), privType,
+ classDef.get());
if (!result) {
return false;
}
}
}
- AnnotationProcessor processor;
if (type->type == ResourceType::kStyleable &&
mOptions.types == JavaClassGeneratorOptions::SymbolTypes::kPublic) {
// When generating a public R class, we don't want Styleable to be part of the API.
// It is only emitted for documentation purposes.
- processor.appendComment("@doconly");
+ classDef->getCommentBuilder()->appendComment("@doconly");
}
- classDef.writeToStream(out, " ", &processor);
+
+ appendJavaDocAnnotations(mOptions.javadocAnnotations, classDef->getCommentBuilder());
+
+ rClass.addMember(std::move(classDef));
}
}
- *out << "}\n";
+ appendJavaDocAnnotations(mOptions.javadocAnnotations, rClass.getCommentBuilder());
+
+ if (!ClassDefinition::writeJavaFile(&rClass, util::utf16ToUtf8(outPackageName),
+ mOptions.useFinal, out)) {
+ return false;
+ }
+
out->flush();
return true;
}
-
-
} // namespace aapt
diff --git a/tools/aapt2/java/JavaClassGenerator.h b/tools/aapt2/java/JavaClassGenerator.h
index 7e46f8c..77e0ed7 100644
--- a/tools/aapt2/java/JavaClassGenerator.h
+++ b/tools/aapt2/java/JavaClassGenerator.h
@@ -28,7 +28,7 @@
namespace aapt {
class AnnotationProcessor;
-class ClassDefinitionWriter;
+class ClassDefinition;
struct JavaClassGeneratorOptions {
/*
@@ -44,6 +44,11 @@
};
SymbolTypes types = SymbolTypes::kAll;
+
+ /**
+ * A list of JavaDoc annotations to add to the comments of all generated classes.
+ */
+ std::vector<std::string> javadocAnnotations;
};
/*
@@ -70,16 +75,15 @@
const std::string& getError() const;
private:
- bool writeEntriesForClass(ClassDefinitionWriter* outClassDef,
- const StringPiece16& packageNameToGenerate,
- const ResourceTablePackage* package,
- const ResourceTableType* type);
+ bool addMembersToTypeClass(const StringPiece16& packageNameToGenerate,
+ const ResourceTablePackage* package,
+ const ResourceTableType* type,
+ ClassDefinition* outTypeClassDef);
- void writeStyleableEntryForClass(ClassDefinitionWriter* outClassDef,
- AnnotationProcessor* processor,
- const StringPiece16& packageNameToGenerate,
- const std::u16string& entryName,
- const Styleable* styleable);
+ void addMembersToStyleableClass(const StringPiece16& packageNameToGenerate,
+ const std::u16string& entryName,
+ const Styleable* styleable,
+ ClassDefinition* outStyleableClassDef);
bool skipSymbol(SymbolState state);
diff --git a/tools/aapt2/java/ManifestClassGenerator.cpp b/tools/aapt2/java/ManifestClassGenerator.cpp
index a9b4c14..be8955e 100644
--- a/tools/aapt2/java/ManifestClassGenerator.cpp
+++ b/tools/aapt2/java/ManifestClassGenerator.cpp
@@ -16,7 +16,7 @@
#include "Source.h"
#include "java/AnnotationProcessor.h"
-#include "java/ClassDefinitionWriter.h"
+#include "java/ClassDefinition.h"
#include "java/ManifestClassGenerator.h"
#include "util/Maybe.h"
#include "xml/XmlDom.h"
@@ -58,8 +58,8 @@
return result;
}
-static bool writeSymbol(IDiagnostics* diag, ClassDefinitionWriter* outClassDef, const Source& source,
- xml::Element* el) {
+static bool writeSymbol(const Source& source, IDiagnostics* diag, xml::Element* el,
+ ClassDefinition* classDef) {
xml::Attribute* attr = el->findAttribute(xml::kSchemaAndroid, u"name");
if (!attr) {
diag->error(DiagMessage(source) << "<" << el->name << "> must define 'android:name'");
@@ -72,54 +72,53 @@
return false;
}
- AnnotationProcessor processor;
- processor.appendComment(el->comment);
- outClassDef->addStringMember(result.value(), &processor, attr->value);
+ std::unique_ptr<StringMember> stringMember = util::make_unique<StringMember>(
+ util::utf16ToUtf8(result.value()), util::utf16ToUtf8(attr->value));
+ stringMember->getCommentBuilder()->appendComment(el->comment);
+
+ classDef->addMember(std::move(stringMember));
return true;
}
-bool ManifestClassGenerator::generate(IDiagnostics* diag, const StringPiece16& package,
- xml::XmlResource* res, std::ostream* out) {
+std::unique_ptr<ClassDefinition> generateManifestClass(IDiagnostics* diag, xml::XmlResource* res) {
xml::Element* el = xml::findRootElement(res->root.get());
if (!el) {
- return false;
+ diag->error(DiagMessage(res->file.source) << "no root tag defined");
+ return {};
}
if (el->name != u"manifest" && !el->namespaceUri.empty()) {
diag->error(DiagMessage(res->file.source) << "no <manifest> root tag defined");
- return false;
+ return {};
}
- *out << "package " << package << ";\n\n"
- << "public final class Manifest {\n";
+ std::unique_ptr<ClassDefinition> permissionClass =
+ util::make_unique<ClassDefinition>("permission", ClassQualifier::Static, false);
+ std::unique_ptr<ClassDefinition> permissionGroupClass =
+ util::make_unique<ClassDefinition>("permission_group", ClassQualifier::Static, false);
bool error = false;
+
std::vector<xml::Element*> children = el->getChildElements();
-
- ClassDefinitionWriterOptions classOptions;
- classOptions.useFinalQualifier = true;
- classOptions.forceCreationIfEmpty = false;
-
- // First write out permissions.
- ClassDefinitionWriter classDef("permission", classOptions);
for (xml::Element* childEl : children) {
- if (childEl->namespaceUri.empty() && childEl->name == u"permission") {
- error |= !writeSymbol(diag, &classDef, res->file.source, childEl);
+ if (childEl->namespaceUri.empty()) {
+ if (childEl->name == u"permission") {
+ error |= !writeSymbol(res->file.source, diag, childEl, permissionClass.get());
+ } else if (childEl->name == u"permission-group") {
+ error |= !writeSymbol(res->file.source, diag, childEl, permissionGroupClass.get());
+ }
}
}
- classDef.writeToStream(out, " ");
- // Next write out permission groups.
- classDef = ClassDefinitionWriter("permission_group", classOptions);
- for (xml::Element* childEl : children) {
- if (childEl->namespaceUri.empty() && childEl->name == u"permission-group") {
- error |= !writeSymbol(diag, &classDef, res->file.source, childEl);
- }
+ if (error) {
+ return {};
}
- classDef.writeToStream(out, " ");
- *out << "}\n";
- return !error;
+ std::unique_ptr<ClassDefinition> manifestClass =
+ util::make_unique<ClassDefinition>("Manifest", ClassQualifier::None, false);
+ manifestClass->addMember(std::move(permissionClass));
+ manifestClass->addMember(std::move(permissionGroupClass));
+ return manifestClass;
}
} // namespace aapt
diff --git a/tools/aapt2/java/ManifestClassGenerator.h b/tools/aapt2/java/ManifestClassGenerator.h
index 226ed23..f565289 100644
--- a/tools/aapt2/java/ManifestClassGenerator.h
+++ b/tools/aapt2/java/ManifestClassGenerator.h
@@ -18,6 +18,7 @@
#define AAPT_JAVA_MANIFESTCLASSGENERATOR_H
#include "Diagnostics.h"
+#include "java/ClassDefinition.h"
#include "util/StringPiece.h"
#include "xml/XmlDom.h"
@@ -25,10 +26,7 @@
namespace aapt {
-struct ManifestClassGenerator {
- bool generate(IDiagnostics* diag, const StringPiece16& package, xml::XmlResource* res,
- std::ostream* out);
-};
+std::unique_ptr<ClassDefinition> generateManifestClass(IDiagnostics* diag, xml::XmlResource* res);
} // namespace aapt
diff --git a/tools/aapt2/java/ManifestClassGenerator_test.cpp b/tools/aapt2/java/ManifestClassGenerator_test.cpp
index fc57ae6f..a9ec318 100644
--- a/tools/aapt2/java/ManifestClassGenerator_test.cpp
+++ b/tools/aapt2/java/ManifestClassGenerator_test.cpp
@@ -22,6 +22,23 @@
namespace aapt {
+static ::testing::AssertionResult getManifestClassText(IAaptContext* context, xml::XmlResource* res,
+ std::string* outStr) {
+ std::unique_ptr<ClassDefinition> manifestClass = generateManifestClass(
+ context->getDiagnostics(), res);
+ if (!manifestClass) {
+ return ::testing::AssertionFailure() << "manifestClass == nullptr";
+ }
+
+ std::stringstream out;
+ if (!manifestClass->writeJavaFile(manifestClass.get(), "android", true, &out)) {
+ return ::testing::AssertionFailure() << "failed to write java file";
+ }
+
+ *outStr = out.str();
+ return ::testing::AssertionSuccess();
+}
+
TEST(ManifestClassGeneratorTest, NameIsProperlyGeneratedFromSymbol) {
std::unique_ptr<IAaptContext> context = test::ContextBuilder().build();
std::unique_ptr<xml::XmlResource> manifest = test::buildXmlDom(R"EOF(
@@ -32,11 +49,8 @@
<permission-group android:name="foo.bar.PERMISSION" />
</manifest>)EOF");
- std::stringstream out;
- ManifestClassGenerator generator;
- ASSERT_TRUE(generator.generate(context->getDiagnostics(), u"android", manifest.get(), &out));
-
- std::string actual = out.str();
+ std::string actual;
+ ASSERT_TRUE(getManifestClassText(context.get(), manifest.get(), &actual));
const size_t permissionClassPos = actual.find("public static final class permission {");
const size_t permissionGroupClassPos =
@@ -87,11 +101,8 @@
<permission android:name="android.permission.SECRET" />
</manifest>)EOF");
- std::stringstream out;
- ManifestClassGenerator generator;
- ASSERT_TRUE(generator.generate(context->getDiagnostics(), u"android", manifest.get(), &out));
-
- std::string actual = out.str();
+ std::string actual;
+ ASSERT_TRUE(getManifestClassText(context.get(), manifest.get(), &actual));
EXPECT_NE(std::string::npos, actual.find(
R"EOF( /**
diff --git a/tools/aapt2/link/Link.cpp b/tools/aapt2/link/Link.cpp
index b84074d..8c8bffa 100644
--- a/tools/aapt2/link/Link.cpp
+++ b/tools/aapt2/link/Link.cpp
@@ -66,6 +66,7 @@
bool staticLib = false;
bool noStaticLibPackages = false;
bool generateNonFinalIds = false;
+ std::vector<std::string> javadocAnnotations;
bool outputToDirectory = false;
bool autoAddOverlay = false;
bool doNotCompressAnything = false;
@@ -762,9 +763,31 @@
return true;
}
+ std::unique_ptr<ClassDefinition> manifestClass = generateManifestClass(
+ mContext->getDiagnostics(), manifestXml);
+
+ if (!manifestClass) {
+ // Something bad happened, but we already logged it, so exit.
+ return false;
+ }
+
+ if (manifestClass->empty()) {
+ // Empty Manifest class, no need to generate it.
+ return true;
+ }
+
+ // Add any JavaDoc annotations to the generated class.
+ for (const std::string& annotation : mOptions.javadocAnnotations) {
+ std::string properAnnotation = "@";
+ properAnnotation += annotation;
+ manifestClass->getCommentBuilder()->appendComment(properAnnotation);
+ }
+
+ const std::string packageUtf8 = util::utf16ToUtf8(mContext->getCompilationPackage());
+
std::string outPath = mOptions.generateJavaClassPath.value();
- file::appendPath(&outPath,
- file::packageToPath(util::utf16ToUtf8(mContext->getCompilationPackage())));
+ file::appendPath(&outPath, file::packageToPath(packageUtf8));
+
if (!file::mkdirs(outPath)) {
mContext->getDiagnostics()->error(
DiagMessage() << "failed to create directory '" << outPath << "'");
@@ -780,13 +803,7 @@
return false;
}
- ManifestClassGenerator generator;
- if (!generator.generate(mContext->getDiagnostics(), mContext->getCompilationPackage(),
- manifestXml, &fout)) {
- return false;
- }
-
- if (!fout) {
+ if (!ClassDefinition::writeJavaFile(manifestClass.get(), packageUtf8, true, &fout)) {
mContext->getDiagnostics()->error(
DiagMessage() << "failed writing to '" << outPath << "': " << strerror(errno));
return false;
@@ -1283,6 +1300,7 @@
if (mOptions.generateJavaClassPath) {
JavaClassGeneratorOptions options;
options.types = JavaClassGeneratorOptions::SymbolTypes::kAll;
+ options.javadocAnnotations = mOptions.javadocAnnotations;
if (mOptions.staticLib || mOptions.generateNonFinalIds) {
options.useFinal = false;
@@ -1423,6 +1441,8 @@
&customJavaPackage)
.optionalFlagList("--extra-packages", "Generate the same R.java but with different "
"package names", &extraJavaPackages)
+ .optionalFlagList("--add-javadoc-annotation", "Adds a JavaDoc annotation to all "
+ "generated Java classes", &options.javadocAnnotations)
.optionalSwitch("--auto-add-overlay", "Allows the addition of new resources in "
"overlays without <add-resource> tags", &options.autoAddOverlay)
.optionalFlag("--rename-manifest-package", "Renames the package in AndroidManifest.xml",
diff --git a/tools/apilint/apilint.py b/tools/apilint/apilint.py
index a8a8c5c..ca2d2e7 100644
--- a/tools/apilint/apilint.py
+++ b/tools/apilint/apilint.py
@@ -980,6 +980,16 @@
warn(clazz, m, "M10", "Methods accepting File should also accept FileDescriptor or streams")
+def verify_manager_list(clazz):
+ """Verifies that managers return List<? extends Parcelable> instead of arrays."""
+
+ if not clazz.name.endswith("Manager"): return
+
+ for m in clazz.methods:
+ if m.typ.startswith("android.") and m.typ.endswith("[]"):
+ warn(clazz, m, None, "Methods should return List<? extends Parcelable> instead of Parcelable[] to support ParceledListSlice under the hood")
+
+
def examine_clazz(clazz):
"""Find all style issues in the given class."""
if clazz.pkg.name.startswith("java"): return
@@ -1025,6 +1035,7 @@
verify_listener_last(clazz)
verify_resource_names(clazz)
verify_files(clazz)
+ verify_manager_list(clazz)
def examine_stream(stream):
diff --git a/tools/fonts/fontchain_lint.py b/tools/fonts/fontchain_lint.py
index 75e837b..b5ed1b5 100755
--- a/tools/fonts/fontchain_lint.py
+++ b/tools/fonts/fontchain_lint.py
@@ -177,9 +177,10 @@
def check_emoji_availability():
emoji_fonts = [font[5] for font in _fallback_chain if 'Zsye' in font[1]]
+ assert len(emoji_fonts) == 1, 'There are %d emoji fonts.' % len(emoji_fonts)
+ emoji_font = emoji_fonts[0]
emoji_chars = _emoji_properties['Emoji']
- for emoji_font in emoji_fonts:
- assert_font_supports_all_of_chars(emoji_font, emoji_chars)
+ assert_font_supports_all_of_chars(emoji_font, emoji_chars)
def check_emoji_defaults():
@@ -273,11 +274,12 @@
hyphens_dir = path.join(target_out, 'usr', 'hyphen-data')
check_hyphens(hyphens_dir)
- ucd_path = sys.argv[2]
- parse_ucd(ucd_path)
- # Temporarily disable emoji checks for Bug 27785690
- # check_emoji_availability()
- # check_emoji_defaults()
+ check_emoji = sys.argv[2]
+ if check_emoji == 'true':
+ ucd_path = sys.argv[3]
+ parse_ucd(ucd_path)
+ check_emoji_availability()
+ check_emoji_defaults()
if __name__ == '__main__':
diff --git a/tools/layoutlib/bridge/src/android/graphics/Path_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Path_Delegate.java
index f5938cf..265ebd1 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Path_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Path_Delegate.java
@@ -423,21 +423,13 @@
}
@LayoutlibDelegate
- /*package*/ static void native_offset(long nPath, float dx, float dy, long dst_path) {
+ /*package*/ static void native_offset(long nPath, float dx, float dy) {
Path_Delegate pathDelegate = sManager.getDelegate(nPath);
if (pathDelegate == null) {
return;
}
- // could be null if the int is 0;
- Path_Delegate dstDelegate = sManager.getDelegate(dst_path);
-
- pathDelegate.offset(dx, dy, dstDelegate);
- }
-
- @LayoutlibDelegate
- /*package*/ static void native_offset(long nPath, float dx, float dy) {
- native_offset(nPath, dx, dy, 0);
+ pathDelegate.offset(dx, dy);
}
@LayoutlibDelegate
@@ -860,21 +852,14 @@
*
* @param dx The amount in the X direction to offset the entire path
* @param dy The amount in the Y direction to offset the entire path
- * @param dst The translated path is written here. If this is null, then
- * the original path is modified.
*/
- public void offset(float dx, float dy, Path_Delegate dst) {
+ public void offset(float dx, float dy) {
GeneralPath newPath = new GeneralPath();
PathIterator iterator = mPath.getPathIterator(new AffineTransform(0, 0, dx, 0, 0, dy));
newPath.append(iterator, false /*connect*/);
-
- if (dst != null) {
- dst.mPath = newPath;
- } else {
- mPath = newPath;
- }
+ mPath = newPath;
}
/**
diff --git a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
index 309c1b8..f9e008e 100644
--- a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
+++ b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
@@ -403,8 +403,15 @@
}
@Override
- public void setNewConfiguration(Configuration arg0) throws RemoteException {
+ public int[] setNewConfiguration(Configuration arg0) throws RemoteException {
// TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public Rect getBoundsForNewConfiguration(int stackId) throws RemoteException {
+ // TODO Auto-generated method stub
+ return null;
}
@Override
@@ -575,4 +582,10 @@
@Override
public void registerShortcutKey(long shortcutCode, IShortcutService service)
throws RemoteException {}
+
+ @Override
+ public void createWallpaperInputConsumer(InputChannel inputChannel) throws RemoteException {}
+
+ @Override
+ public void removeWallpaperInputConsumer() throws RemoteException {}
}
diff --git a/tools/layoutlib/bridge/src/android/view/RenderNode_Delegate.java b/tools/layoutlib/bridge/src/android/view/RenderNode_Delegate.java
index 1465f50..24f7887 100644
--- a/tools/layoutlib/bridge/src/android/view/RenderNode_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/view/RenderNode_Delegate.java
@@ -55,7 +55,7 @@
private String mName;
@LayoutlibDelegate
- /*package*/ static long nCreate(String name) {
+ /*package*/ static long nCreate(RenderNode thisRenderNode, String name) {
RenderNode_Delegate renderNodeDelegate = new RenderNode_Delegate();
renderNodeDelegate.mName = name;
return sManager.addNewDelegate(renderNodeDelegate);
diff --git a/tools/layoutlib/bridge/src/com/android/internal/util/VirtualRefBasePtr_Delegate.java b/tools/layoutlib/bridge/src/com/android/internal/util/VirtualRefBasePtr_Delegate.java
new file mode 100644
index 0000000..01fe45d
--- /dev/null
+++ b/tools/layoutlib/bridge/src/com/android/internal/util/VirtualRefBasePtr_Delegate.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.util;
+
+import com.android.layoutlib.bridge.impl.DelegateManager;
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
+
+import android.util.LongSparseLongArray;
+
+/**
+ * Delegate used to provide new implementation the native methods of {@link VirtualRefBasePtr}
+ *
+ * Through the layoutlib_create tool, the original native methods of VirtualRefBasePtr have been
+ * replaced by calls to methods of the same name in this delegate class.
+ *
+ */
+@SuppressWarnings("unused")
+public class VirtualRefBasePtr_Delegate {
+ private static final DelegateManager<Object> sManager = new DelegateManager<>(Object.class);
+ private static final LongSparseLongArray sRefCount = new LongSparseLongArray();
+
+ @LayoutlibDelegate
+ /*package*/ static synchronized void nIncStrong(long ptr) {
+ long counter = sRefCount.get(ptr);
+ sRefCount.put(ptr, ++counter);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static synchronized void nDecStrong(long ptr) {
+ long counter = sRefCount.get(ptr);
+
+ if (counter > 1) {
+ sRefCount.put(ptr, --counter);
+ } else {
+ sRefCount.delete(ptr);
+ sManager.removeJavaReferenceFor(ptr);
+ }
+ }
+}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
index c8e3d03..9e50ee8 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
@@ -24,6 +24,7 @@
import com.android.ide.common.rendering.api.Result;
import com.android.ide.common.rendering.api.Result.Status;
import com.android.ide.common.rendering.api.SessionParams;
+import com.android.layoutlib.bridge.android.RenderParamsFlags;
import com.android.layoutlib.bridge.impl.RenderDrawable;
import com.android.layoutlib.bridge.impl.RenderSessionImpl;
import com.android.layoutlib.bridge.util.DynamicIdMap;
@@ -408,7 +409,9 @@
/**
* Starts a layout session by inflating and rendering it. The method returns a
* {@link RenderSession} on which further actions can be taken.
- *
+ * <p/>
+ * If {@link SessionParams} includes the {@link RenderParamsFlags#FLAG_DO_NOT_RENDER_ON_CREATE},
+ * this method will only inflate the layout but will NOT render it.
* @param params the {@link SessionParams} object with all the information necessary to create
* the scene.
* @return a new {@link RenderSession} object that contains the result of the layout.
@@ -424,7 +427,10 @@
lastResult = scene.init(params.getTimeout());
if (lastResult.isSuccess()) {
lastResult = scene.inflate();
- if (lastResult.isSuccess()) {
+
+ boolean doNotRenderOnCreate = Boolean.TRUE.equals(
+ params.getFlag(RenderParamsFlags.FLAG_DO_NOT_RENDER_ON_CREATE));
+ if (lastResult.isSuccess() && !doNotRenderOnCreate) {
lastResult = scene.render(true /*freshRender*/);
}
}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowSession.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowSession.java
index 53adb41..5a6a00f 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowSession.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowSession.java
@@ -97,7 +97,6 @@
@Override
public void repositionChild(IWindow window, int left, int top, int right, int bottom,
- int requestedWidth, int requestedHeight,
long deferTransactionUntilFrame, Rect outFrame) {
// pass for now.
return;
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/RenderParamsFlags.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/RenderParamsFlags.java
index bd17a2f..051de90 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/RenderParamsFlags.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/RenderParamsFlags.java
@@ -53,6 +53,12 @@
*/
public static final Key<Boolean> FLAG_KEY_XML_FILE_PARSER_SUPPORT =
new Key<Boolean>("xmlFileParser", Boolean.class);
+ /**
+ * To tell LayoutLib to not render when creating a new session. This allows controlling when the first
+ * layout rendering will happen.
+ */
+ public static final Key<Boolean> FLAG_DO_NOT_RENDER_ON_CREATE =
+ new Key<Boolean>("doNotRenderOnCreate", Boolean.class);
// Disallow instances.
private RenderParamsFlags() {}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/FrameworkActionBarWrapper.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/FrameworkActionBarWrapper.java
index af6ba24..2cdc647 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/FrameworkActionBarWrapper.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/FrameworkActionBarWrapper.java
@@ -43,6 +43,7 @@
import android.view.ViewGroup;
import android.view.WindowCallback;
import android.widget.ActionMenuPresenter;
+import android.widget.ActionMenuView;
import android.widget.Toolbar;
import android.widget.Toolbar_Accessor;
@@ -196,11 +197,16 @@
@Override
protected void inflateMenus() {
super.inflateMenus();
- // Inflating the menus doesn't initialize the ActionMenuPresenter. Setting a fake menu
- // and then setting it back does the trick.
+ // Inflating the menus isn't enough. ActionMenuPresenter needs to be initialized too.
MenuBuilder menu = getMenuBuilder();
DecorToolbar decorToolbar = getDecorToolbar();
+ // Setting a menu different from the above initializes the presenter.
decorToolbar.setMenu(new MenuBuilder(getActionMenuContext()), null);
+ // ActionMenuView needs to be recreated to be able to set the menu back.
+ ActionMenuPresenter presenter = getActionMenuPresenter();
+ if (presenter != null) {
+ presenter.setMenuView(new ActionMenuView(getPopupContext()));
+ }
decorToolbar.setMenu(menu, null);
}
@@ -255,7 +261,7 @@
@NonNull ActionBarView actionBarView) {
super(context, callback, new WindowDecorActionBar(decorContentRoot));
mActionBarView = actionBarView;
- mActionBar = ((WindowDecorActionBar) super.mActionBar);
+ mActionBar = (WindowDecorActionBar) super.mActionBar;
mDecorContentRoot = decorContentRoot;
}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/DelegateManager.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/DelegateManager.java
index baf2e2e..c59b1a6 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/DelegateManager.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/DelegateManager.java
@@ -22,9 +22,11 @@
import android.annotation.Nullable;
import android.util.SparseArray;
+import java.io.PrintStream;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.List;
+import java.util.concurrent.atomic.AtomicLong;
/**
* Manages native delegates.
@@ -73,14 +75,14 @@
public final class DelegateManager<T> {
@SuppressWarnings("FieldCanBeLocal")
private final Class<T> mClass;
- private final SparseWeakArray<T> mDelegates = new SparseWeakArray<T>();
+ private static final SparseWeakArray<Object> sDelegates = new SparseWeakArray<>();
/** list used to store delegates when their main object holds a reference to them.
* This is to ensure that the WeakReference in the SparseWeakArray doesn't get GC'ed
* @see #addNewDelegate(Object)
* @see #removeJavaReferenceFor(long)
*/
- private final List<T> mJavaReferences = new ArrayList<T>();
- private int mDelegateCounter = 0;
+ private static final List<Object> sJavaReferences = new ArrayList<>();
+ private static final AtomicLong sDelegateCounter = new AtomicLong(1);
public DelegateManager(Class<T> theClass) {
mClass = theClass;
@@ -97,9 +99,12 @@
* @return the delegate or null if not found.
*/
@Nullable
- public synchronized T getDelegate(long native_object) {
+ public T getDelegate(long native_object) {
if (native_object > 0) {
- T delegate = mDelegates.get(native_object);
+ Object delegate;
+ synchronized (DelegateManager.class) {
+ delegate = sDelegates.get(native_object);
+ }
if (Debug.DEBUG) {
if (delegate == null) {
@@ -109,7 +114,8 @@
}
assert delegate != null;
- return delegate;
+ //noinspection unchecked
+ return (T)delegate;
}
return null;
}
@@ -119,12 +125,13 @@
* @param newDelegate the delegate to add
* @return a unique native int to identify the delegate
*/
- public synchronized long addNewDelegate(T newDelegate) {
- long native_object = ++mDelegateCounter;
-
- mDelegates.put(native_object, newDelegate);
- assert !mJavaReferences.contains(newDelegate);
- mJavaReferences.add(newDelegate);
+ public long addNewDelegate(T newDelegate) {
+ long native_object = sDelegateCounter.getAndIncrement();
+ synchronized (DelegateManager.class) {
+ sDelegates.put(native_object, newDelegate);
+ assert !sJavaReferences.contains(newDelegate);
+ sJavaReferences.add(newDelegate);
+ }
if (Debug.DEBUG) {
System.out.println(
@@ -140,14 +147,23 @@
* Removes the main reference on the given delegate.
* @param native_object the native integer representing the delegate.
*/
- public synchronized void removeJavaReferenceFor(long native_object) {
- T delegate = getDelegate(native_object);
+ public void removeJavaReferenceFor(long native_object) {
+ synchronized (DelegateManager.class) {
+ T delegate = getDelegate(native_object);
- if (Debug.DEBUG) {
- System.out.println("Removing main Java ref on " + mClass.getSimpleName() +
- " with int " + native_object);
+ if (Debug.DEBUG) {
+ System.out.println("Removing main Java ref on " + mClass.getSimpleName() +
+ " with int " + native_object);
+ }
+
+ sJavaReferences.remove(delegate);
}
+ }
- mJavaReferences.remove(delegate);
+ public synchronized static void dump(PrintStream out) {
+ for (Object reference : sJavaReferences) {
+ int idx = sDelegates.indexOfValue(reference);
+ out.printf("[%d] %s\n", sDelegates.keyAt(idx), reference.getClass().getSimpleName());
+ }
}
}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java
index 016825a..ce7104e 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java
@@ -267,6 +267,34 @@
}
/**
+ * Renders the given view hierarchy to the passed canvas and returns the result of the render
+ * operation.
+ * @param canvas an optional canvas to render the views to. If null, only the measure and
+ * layout steps will be executed.
+ */
+ private static Result render(@NonNull BridgeContext context, @NonNull ViewGroup viewRoot,
+ @Nullable Canvas canvas, int width, int height) {
+ // measure again with the size we need
+ // This must always be done before the call to layout
+ measureView(viewRoot, null /*measuredView*/,
+ width, MeasureSpec.EXACTLY,
+ height, MeasureSpec.EXACTLY);
+
+ // now do the layout.
+ viewRoot.layout(0, 0, width, height);
+ handleScrolling(context, viewRoot);
+
+ if (canvas == null) {
+ return SUCCESS.createResult();
+ }
+
+ AttachInfo_Accessor.dispatchOnPreDraw(viewRoot);
+ viewRoot.draw(canvas);
+
+ return SUCCESS.createResult();
+ }
+
+ /**
* Renders the scene.
* <p>
* {@link #acquire(long)} must have been called before this.
@@ -367,24 +395,12 @@
}
}
- // measure again with the size we need
- // This must always be done before the call to layout
- measureView(mViewRoot, null /*measuredView*/,
- mMeasuredScreenWidth, MeasureSpec.EXACTLY,
- mMeasuredScreenHeight, MeasureSpec.EXACTLY);
-
- // now do the layout.
- mViewRoot.layout(0, 0, mMeasuredScreenWidth, mMeasuredScreenHeight);
-
- handleScrolling(mViewRoot);
-
+ Result renderResult = SUCCESS.createResult();
if (params.isLayoutOnly()) {
// delete the canvas and image to reset them on the next full rendering
mImage = null;
mCanvas = null;
} else {
- AttachInfo_Accessor.dispatchOnPreDraw(mViewRoot);
-
// draw the views
// create the BufferedImage into which the layout will be rendered.
boolean newImage = false;
@@ -446,6 +462,9 @@
if (mElapsedFrameTimeNanos >= 0) {
long initialTime = System_Delegate.nanoTime();
if (!mFirstFrameExecuted) {
+ // We need to run an initial draw call to initialize the animations
+ render(getContext(), mViewRoot, mCanvas, 0, 0);
+
// The first frame will initialize the animations
Choreographer_Delegate.doFrame(initialTime);
mFirstFrameExecuted = true;
@@ -453,14 +472,15 @@
// Second frame will move the animations
Choreographer_Delegate.doFrame(initialTime + mElapsedFrameTimeNanos);
}
- mViewRoot.draw(mCanvas);
+ renderResult = render(getContext(), mViewRoot, mCanvas, mMeasuredScreenWidth,
+ mMeasuredScreenHeight);
}
mSystemViewInfoList = visitAllChildren(mViewRoot, 0, params.getExtendedViewInfoMode(),
false);
// success!
- return SUCCESS.createResult();
+ return renderResult;
} catch (Throwable e) {
// get the real cause of the exception.
Throwable t = e;
@@ -488,7 +508,7 @@
* @return the measured width/height if measuredView is non-null, null otherwise.
*/
@SuppressWarnings("deprecation") // For the use of Pair
- private Pair<Integer, Integer> measureView(ViewGroup viewToMeasure, View measuredView,
+ private static Pair<Integer, Integer> measureView(ViewGroup viewToMeasure, View measuredView,
int width, int widthMode, int height, int heightMode) {
int w_spec = MeasureSpec.makeMeasureSpec(width, widthMode);
int h_spec = MeasureSpec.makeMeasureSpec(height, heightMode);
@@ -1061,8 +1081,7 @@
* the component supports nested scrolling attempt that first, then use the unconsumed scroll
* part to scroll the content in the component.
*/
- private void handleScrolling(View view) {
- BridgeContext context = getContext();
+ private static void handleScrolling(BridgeContext context, View view) {
int scrollPosX = context.getScrollXPos(view);
int scrollPosY = context.getScrollYPos(view);
if (scrollPosX != 0 || scrollPosY != 0) {
@@ -1080,7 +1099,7 @@
}
}
if (scrollPosX != 0 || scrollPosY != 0) {
- view.scrollBy(scrollPosX, scrollPosY);
+ view.scrollTo(scrollPosX, scrollPosY);
}
}
@@ -1090,7 +1109,7 @@
ViewGroup group = (ViewGroup) view;
for (int i = 0; i < group.getChildCount(); i++) {
View child = group.getChildAt(i);
- handleScrolling(child);
+ handleScrolling(context, child);
}
}
diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/res/layout/scrolled.xml b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/res/layout/scrolled.xml
index a5ebc2e..a07498c 100644
--- a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/res/layout/scrolled.xml
+++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/res/layout/scrolled.xml
@@ -2,8 +2,8 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
- android:scrollX="10px"
- android:scrollY="30px">
+ android:scrollX="30px"
+ android:scrollY="90px">
<LinearLayout
android:layout_width="60dp"
android:layout_height="60dp"
@@ -29,8 +29,8 @@
android:layout_width="200dp"
android:layout_height="400dp"
android:orientation="vertical"
- android:scrollX="-30px"
- android:scrollY="150px">
+ android:scrollX="-90px"
+ android:scrollY="450px">
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="60dp"
diff --git a/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/Main.java b/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/Main.java
index a5561fa..034c8b2 100644
--- a/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/Main.java
+++ b/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/Main.java
@@ -30,7 +30,9 @@
import com.android.io.FolderWrapper;
import com.android.layoutlib.bridge.Bridge;
import com.android.layoutlib.bridge.android.BridgeContext;
+import com.android.layoutlib.bridge.android.RenderParamsFlags;
import com.android.layoutlib.bridge.impl.RenderAction;
+import com.android.layoutlib.bridge.impl.DelegateManager;
import com.android.layoutlib.bridge.intensive.setup.ConfigGenerator;
import com.android.layoutlib.bridge.intensive.setup.LayoutLibTestCallback;
import com.android.layoutlib.bridge.intensive.setup.LayoutPullParser;
@@ -52,6 +54,7 @@
import java.io.File;
import java.io.IOException;
+import java.lang.ref.WeakReference;
import java.net.URL;
import java.util.Arrays;
import java.util.concurrent.TimeUnit;
@@ -298,6 +301,16 @@
renderAndVerify("allwidgets.xml", "allwidgets_tab.png", ConfigGenerator.NEXUS_7_2012);
}
+ private static void gc() {
+ // See RuntimeUtil#gc in jlibs (http://jlibs.in/)
+ Object obj = new Object();
+ WeakReference ref = new WeakReference<Object>(obj);
+ obj = null;
+ while(ref.get() != null) {
+ System.gc();
+ }
+ }
+
@AfterClass
public static void tearDown() {
sLayoutLibLog = null;
@@ -305,6 +318,11 @@
sProjectResources = null;
sLogger = null;
sBridge = null;
+
+ gc();
+
+ System.out.println("Objects still linked from the DelegateManager:");
+ DelegateManager.dump(System.out);
}
/** Test expand_layout.xml */
@@ -547,7 +565,7 @@
sFrameworkRepo.getConfiguredResources(config),
themeName, isProjectTheme);
- return new SessionParams(
+ SessionParams sessionParams = new SessionParams(
layoutParser,
renderingMode,
null /*used for caching*/,
@@ -557,6 +575,8 @@
0,
targetSdk,
getLayoutLog());
+ sessionParams.setFlag(RenderParamsFlags.FLAG_DO_NOT_RENDER_ON_CREATE, true);
+ return sessionParams;
}
private static LayoutLog getLayoutLog() {
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java
index 1a00cc9..483bddc 100644
--- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java
@@ -302,6 +302,7 @@
"android.text.StaticLayout",
"android.util.PathParser",
"android.view.Display",
+ "com.android.internal.util.VirtualRefBasePtr",
"com.android.internal.view.animation.NativeInterpolatorFactoryHelper",
"libcore.icu.ICU",
};
diff --git a/wifi/java/android/net/wifi/WifiActivityEnergyInfo.java b/wifi/java/android/net/wifi/WifiActivityEnergyInfo.java
index 035317e..4c38c9b 100644
--- a/wifi/java/android/net/wifi/WifiActivityEnergyInfo.java
+++ b/wifi/java/android/net/wifi/WifiActivityEnergyInfo.java
@@ -19,6 +19,8 @@
import android.os.Parcel;
import android.os.Parcelable;
+import java.util.Arrays;
+
/**
* Record of energy and activity information from controller and
* underlying wifi stack state. Timestamp the record with elapsed
@@ -44,6 +46,11 @@
/**
* @hide
*/
+ public long[] mControllerTxTimePerLevelMs;
+
+ /**
+ * @hide
+ */
public long mControllerRxTimeMs;
/**
@@ -62,10 +69,12 @@
public static final int STACK_STATE_STATE_IDLE = 3;
public WifiActivityEnergyInfo(long timestamp, int stackState,
- long txTime, long rxTime, long idleTime, long energyUsed) {
+ long txTime, long[] txTimePerLevel, long rxTime, long idleTime,
+ long energyUsed) {
mTimestamp = timestamp;
mStackState = stackState;
mControllerTxTimeMs = txTime;
+ mControllerTxTimePerLevelMs = txTimePerLevel;
mControllerRxTimeMs = rxTime;
mControllerIdleTimeMs = idleTime;
mControllerEnergyUsed = energyUsed;
@@ -77,6 +86,7 @@
+ " timestamp=" + mTimestamp
+ " mStackState=" + mStackState
+ " mControllerTxTimeMs=" + mControllerTxTimeMs
+ + " mControllerTxTimePerLevelMs=" + Arrays.toString(mControllerTxTimePerLevelMs)
+ " mControllerRxTimeMs=" + mControllerRxTimeMs
+ " mControllerIdleTimeMs=" + mControllerIdleTimeMs
+ " mControllerEnergyUsed=" + mControllerEnergyUsed
@@ -89,11 +99,12 @@
long timestamp = in.readLong();
int stackState = in.readInt();
long txTime = in.readLong();
+ long[] txTimePerLevel = in.createLongArray();
long rxTime = in.readLong();
long idleTime = in.readLong();
long energyUsed = in.readLong();
return new WifiActivityEnergyInfo(timestamp, stackState,
- txTime, rxTime, idleTime, energyUsed);
+ txTime, txTimePerLevel, rxTime, idleTime, energyUsed);
}
public WifiActivityEnergyInfo[] newArray(int size) {
return new WifiActivityEnergyInfo[size];
@@ -104,6 +115,7 @@
out.writeLong(mTimestamp);
out.writeInt(mStackState);
out.writeLong(mControllerTxTimeMs);
+ out.writeLongArray(mControllerTxTimePerLevelMs);
out.writeLong(mControllerRxTimeMs);
out.writeLong(mControllerIdleTimeMs);
out.writeLong(mControllerEnergyUsed);
@@ -128,6 +140,16 @@
}
/**
+ * @return tx time at power level provided in ms
+ */
+ public long getControllerTxTimeMillisAtLevel(int level) {
+ if (level < mControllerTxTimePerLevelMs.length) {
+ return mControllerTxTimePerLevelMs[level];
+ }
+ return 0;
+ }
+
+ /**
* @return rx time in ms
*/
public long getControllerRxTimeMillis() {
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index 06dea07..fb2bdd4 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -938,6 +938,15 @@
private boolean mSeenInLastQualifiedNetworkSelection;
/**
+ * Boolean indicating if we have ever successfully connected to this network.
+ *
+ * This value will be set to true upon a successful connection.
+ * This value will be set to false if a previous value was not stored in the config or if
+ * the credentials are updated (ex. a password change).
+ */
+ private boolean mHasEverConnected;
+
+ /**
* set whether this network is visible in latest Qualified Network Selection
* @param seen value set to candidate
*/
@@ -1027,7 +1036,18 @@
return QUALITY_NETWORK_SELECTION_STATUS[mStatus];
}
- private NetworkSelectionStatus() {};
+ public void setHasEverConnected(boolean value) {
+ mHasEverConnected = value;
+ }
+
+ public boolean getHasEverConnected() {
+ return mHasEverConnected;
+ }
+
+ private NetworkSelectionStatus() {
+ // previously stored configs will not have this parameter, so we default to false.
+ mHasEverConnected = false;
+ };
/**
* @param reason specific error reason
@@ -1226,6 +1246,7 @@
mNetworkSelectionBSSID = source.mNetworkSelectionBSSID;
setConnectChoice(source.getConnectChoice());
setConnectChoiceTimestamp(source.getConnectChoiceTimestamp());
+ setHasEverConnected(source.getHasEverConnected());
}
public void writeToParcel(Parcel dest) {
@@ -1244,6 +1265,7 @@
} else {
dest.writeInt(CONNECT_CHOICE_NOT_EXISTS);
}
+ dest.writeInt(getHasEverConnected() ? 1 : 0);
}
public void readFromParcel(Parcel in) {
@@ -1262,6 +1284,7 @@
setConnectChoice(null);
setConnectChoiceTimestamp(INVALID_NETWORK_SELECTION_DISABLE_TIMESTAMP);
}
+ setHasEverConnected(in.readInt() != 0);
}
}
@@ -1389,6 +1412,8 @@
sbuf.append(" connect choice set time: ").append(mNetworkSelectionStatus
.getConnectChoiceTimestamp());
}
+ sbuf.append(" hasEverConnected: ")
+ .append(mNetworkSelectionStatus.getHasEverConnected()).append("\n");
if (this.numAssociation > 0) {
sbuf.append(" numAssociation ").append(this.numAssociation).append("\n");
diff --git a/wifi/java/android/net/wifi/WifiInfo.java b/wifi/java/android/net/wifi/WifiInfo.java
index 9f8af6e..8d5efba 100644
--- a/wifi/java/android/net/wifi/WifiInfo.java
+++ b/wifi/java/android/net/wifi/WifiInfo.java
@@ -320,7 +320,8 @@
if (!TextUtils.isEmpty(unicode)) {
return "\"" + unicode + "\"";
} else {
- return mWifiSsid.getHexString();
+ String hex = mWifiSsid.getHexString();
+ return (hex != null) ? hex : WifiSsid.NONE;
}
}
return WifiSsid.NONE;
diff --git a/wifi/java/android/net/wifi/WifiLinkLayerStats.java b/wifi/java/android/net/wifi/WifiLinkLayerStats.java
index 1de4fd8..edd400b 100644
--- a/wifi/java/android/net/wifi/WifiLinkLayerStats.java
+++ b/wifi/java/android/net/wifi/WifiLinkLayerStats.java
@@ -19,6 +19,8 @@
import android.os.Parcelable;
import android.os.Parcel;
+import java.util.Arrays;
+
/**
* A class representing link layer statistics collected over a Wifi Interface.
*/
@@ -101,6 +103,8 @@
/** {@hide} */
public int tx_time;
/** {@hide} */
+ public int[] tx_time_per_level;
+ /** {@hide} */
public int rx_time;
/** {@hide} */
public int on_time_scan;
@@ -141,9 +145,10 @@
.append(" lost=").append(Long.toString(this.lostmpdu_vo))
.append(" retries=").append(Long.toString(this.retries_vo)).append('\n');
sbuf.append(" on_time : ").append(Integer.toString(this.on_time))
- .append(" tx_time=").append(Integer.toString(this.tx_time))
.append(" rx_time=").append(Integer.toString(this.rx_time))
- .append(" scan_time=").append(Integer.toString(this.on_time_scan)).append('\n');
+ .append(" scan_time=").append(Integer.toString(this.on_time_scan)).append('\n')
+ .append(" tx_time=").append(Integer.toString(this.tx_time))
+ .append(" tx_time_per_level=" + Arrays.toString(tx_time_per_level));
return sbuf.toString();
}
@@ -179,6 +184,7 @@
dest.writeString(BSSID);
dest.writeInt(on_time);
dest.writeInt(tx_time);
+ dest.writeIntArray(tx_time_per_level);
dest.writeInt(rx_time);
dest.writeInt(on_time_scan);
}
@@ -192,6 +198,7 @@
stats.BSSID = in.readString();
stats.on_time = in.readInt();
stats.tx_time = in.readInt();
+ stats.tx_time_per_level = in.createIntArray();
stats.rx_time = in.readInt();
stats.on_time_scan = in.readInt();
return stats;
diff --git a/wifi/java/android/net/wifi/WifiScanner.java b/wifi/java/android/net/wifi/WifiScanner.java
index ecf5447..73ddbbc 100644
--- a/wifi/java/android/net/wifi/WifiScanner.java
+++ b/wifi/java/android/net/wifi/WifiScanner.java
@@ -27,6 +27,7 @@
import android.os.Parcel;
import android.os.Parcelable;
import android.os.RemoteException;
+import android.os.WorkSource;
import android.util.Log;
import android.util.SparseArray;
@@ -160,6 +161,11 @@
*/
public static final int REPORT_EVENT_NO_BATCH = (1 << 2);
+
+ /** {@hide} */
+ public static final String SCAN_PARAMS_SCAN_SETTINGS_KEY = "ScanSettings";
+ /** {@hide} */
+ public static final String SCAN_PARAMS_WORK_SOURCE_KEY = "WorkSource";
/**
* scan configuration parameters to be sent to {@link #startBackgroundScan}
*/
@@ -322,6 +328,11 @@
return mFlags;
}
+ /** {@hide} */
+ public int getBucketsScanned() {
+ return mBucketsScanned;
+ }
+
public ScanResult[] getResults() {
return mResults;
}
@@ -656,12 +667,29 @@
* scans should also not share this object.
*/
public void startBackgroundScan(ScanSettings settings, ScanListener listener) {
+ startBackgroundScan(settings, listener, null);
+ }
+
+ /** start wifi scan in background
+ * @param settings specifies various parameters for the scan; for more information look at
+ * {@link ScanSettings}
+ * @param workSource WorkSource to blame for power usage
+ * @param listener specifies the object to report events to. This object is also treated as a
+ * key for this scan, and must also be specified to cancel the scan. Multiple
+ * scans should also not share this object.
+ */
+ public void startBackgroundScan(ScanSettings settings, ScanListener listener,
+ WorkSource workSource) {
Preconditions.checkNotNull(listener, "listener cannot be null");
int key = addListener(listener);
if (key == INVALID_KEY) return;
validateChannel();
- sAsyncChannel.sendMessage(CMD_START_BACKGROUND_SCAN, 0, key, settings);
+ Bundle scanParams = new Bundle();
+ scanParams.putParcelable(SCAN_PARAMS_SCAN_SETTINGS_KEY, settings);
+ scanParams.putParcelable(SCAN_PARAMS_WORK_SOURCE_KEY, workSource);
+ sAsyncChannel.sendMessage(CMD_START_BACKGROUND_SCAN, 0, key, scanParams);
}
+
/**
* stop an ongoing wifi scan
* @param listener specifies which scan to cancel; must be same object as passed in {@link
@@ -693,11 +721,27 @@
* scans should also not share this object.
*/
public void startScan(ScanSettings settings, ScanListener listener) {
+ startScan(settings, listener, null);
+ }
+
+ /**
+ * starts a single scan and reports results asynchronously
+ * @param settings specifies various parameters for the scan; for more information look at
+ * {@link ScanSettings}
+ * @param workSource WorkSource to blame for power usage
+ * @param listener specifies the object to report events to. This object is also treated as a
+ * key for this scan, and must also be specified to cancel the scan. Multiple
+ * scans should also not share this object.
+ */
+ public void startScan(ScanSettings settings, ScanListener listener, WorkSource workSource) {
Preconditions.checkNotNull(listener, "listener cannot be null");
int key = addListener(listener);
if (key == INVALID_KEY) return;
validateChannel();
- sAsyncChannel.sendMessage(CMD_START_SINGLE_SCAN, 0, key, settings);
+ Bundle scanParams = new Bundle();
+ scanParams.putParcelable(SCAN_PARAMS_SCAN_SETTINGS_KEY, settings);
+ scanParams.putParcelable(SCAN_PARAMS_WORK_SOURCE_KEY, workSource);
+ sAsyncChannel.sendMessage(CMD_START_SINGLE_SCAN, 0, key, scanParams);
}
/**
@@ -716,7 +760,6 @@
private void startPnoScan(ScanSettings scanSettings, PnoSettings pnoSettings, int key) {
// Bundle up both the settings and send it across.
Bundle pnoParams = new Bundle();
- if (pnoParams == null) return;
// Set the PNO scan flag.
scanSettings.isPnoScan = true;
pnoParams.putParcelable(PNO_PARAMS_SCAN_SETTINGS_KEY, scanSettings);
diff --git a/wifi/java/android/net/wifi/WifiSsid.java b/wifi/java/android/net/wifi/WifiSsid.java
index f8ba95d..c53cd3c 100644
--- a/wifi/java/android/net/wifi/WifiSsid.java
+++ b/wifi/java/android/net/wifi/WifiSsid.java
@@ -205,7 +205,7 @@
for (int i = 0; i < octets.size(); i++) {
out += String.format(Locale.US, "%02x", ssidbytes[i]);
}
- return out;
+ return (octets.size() > 0) ? out : null;
}
/** Implement the Parcelable interface {@hide} */